├── DEXTemplate.bt ├── README └── smali.vim /DEXTemplate.bt: -------------------------------------------------------------------------------- 1 | //-------------------------------------- 2 | //--- 010 Editor v3.1.3 Binary Template 3 | // 4 | // File: DEXTemplate.bt 5 | // Author: Jon Larimer 6 | // Tim Strazzere 7 | // Revision: 1.3 8 | // Purpose: A template for analyzing Dalvik VM (Android) DEX files 9 | // 10 | // License: This file is released into the public domain. People may 11 | // use it for any purpose, commercial or otherwise. 12 | //-------------------------------------- 13 | // Version 1.3 (2013-2-7) 14 | // 15 | // FIXED: 16 | // - Actually fixed the on-demand structs issue. Template appears to 17 | // run much faster (previous update introduced bugs) 18 | // - Properly configured the optimize=true|false flags for structs 19 | // 20 | // Version 1.2 (2012-12-17) 21 | // 22 | // FIXED: 23 | // - Attempting to convert some structs over to on-demand structs, 24 | // this should reduce some memory overhead according to 010Editor 25 | // docs. 26 | // 27 | // Version 1.1 (2012-10-08) 28 | // 29 | // FIXED: 30 | // - Same set of known issues below, though I've added some simple 31 | // coloring to aid with visual inspection of APKS. 32 | // - Linked section is called out in red 33 | // - If there is a larger than normal header, it will be colored red 34 | // and bundled into the "extra_padding" section of the header for 35 | // easier inspection 36 | // 37 | // NEW ISSUES 38 | // - Only color the linked section if it isn't null 39 | // 40 | // 41 | // Version 1.0 (2011-05-10) 42 | // 43 | // KNOWN ISSUES: 44 | // - display of floats and doubles in encoded_value is incorrect 45 | // - display of MUTF-8 strings may be incorrect 46 | // - doesn't handle big endian (byte swapped) files 47 | // - doesn't disassemble DEX instructions 48 | // - only decodes partial information from optimized (ODEX/DexOpt) files 49 | // - could use a bit of refactoring and removing duplicate code 50 | // - not decoding items in the map_list structure - they're already 51 | // referenced through other items in the header so adding them 52 | // in the map_list would be reduntant 53 | 54 | LittleEndian(); 55 | 56 | #define NO_INDEX (0xFFFFFFFF) 57 | #define ENDIAN_CONSTANT (0x12345678) 58 | #define REVERSE_ENDIAN_CONSTANT (0x78563412); 59 | 60 | // offset used when seeking within a dex file inside of an odex wrapper 61 | local int odexpad = 0; 62 | 63 | // utility type to show the SHA1 hash in the value column 64 | typedef ubyte SHA1[20] ; 65 | 66 | string SHA1Read(SHA1 sig) { 67 | string ret; 68 | string tmp; 69 | int i; 70 | 71 | for(i = 0; i<20; i++) { 72 | SPrintf(tmp, "%.2X", sig[i]); 73 | ret += tmp; 74 | } 75 | 76 | return ret; 77 | } 78 | 79 | // utility for reading/checking the magic value 80 | typedef struct { 81 | char dex[3]; 82 | char newline; 83 | char ver[3]; 84 | char zero; 85 | 86 | // XXX not checking the version, but it should be 035 87 | if((Strcmp(dex, "dex") && Strcmp(dex, "dey")) || 88 | newline != '\n' || 89 | zero != 0) { 90 | 91 | Warning("Invalid DEX file"); 92 | return -1; 93 | } 94 | } dex_magic ; 95 | 96 | string DexMagicRead(dex_magic &m) { 97 | string s; 98 | SPrintf(s, "%s %s", m.dex, m.ver); 99 | return s; 100 | } 101 | 102 | ////////////////////////////////////////////////// 103 | // LEB128 stuff 104 | ////////////////////////////////////////////////// 105 | 106 | // struct to read a uleb128 value. uleb128's are a variable-length encoding for 107 | // a 32 bit value. some of the uleb128/sleb128 code was adapted from dalvik's 108 | // libdex/Leb128.h 109 | 110 | typedef struct { 111 | ubyte val ; 112 | if(val > 0x7f) { 113 | ubyte val ; 114 | if (val > 0x7f) { 115 | ubyte val ; 116 | if(val > 0x7f) { 117 | ubyte val ; 118 | if(val > 0x7f) { 119 | ubyte val ; 120 | } 121 | } 122 | } 123 | } 124 | } uleb128 ; 125 | 126 | // get the actual uint value of the uleb128 127 | uint uleb128_value(uleb128 &u) { 128 | local uint result; 129 | local ubyte cur; 130 | 131 | result = u.val[0]; 132 | if(result > 0x7f) { 133 | cur = u.val[1]; 134 | result = (result & 0x7f) | (uint)((cur & 0x7f) << 7); 135 | if(cur > 0x7f) { 136 | cur = u.val[2]; 137 | result |= (uint)(cur & 0x7f) << 14; 138 | if(cur > 0x7f) { 139 | cur = u.val[3]; 140 | result |= (uint)(cur & 0x7f) << 21; 141 | if(cur > 0x7f) { 142 | cur = u.val[4]; 143 | result |= (uint)cur << 28; 144 | } 145 | } 146 | } 147 | } 148 | 149 | return result; 150 | } 151 | 152 | typedef struct uleb128 uleb128p1; 153 | 154 | int uleb128p1_value(uleb128 &u) { 155 | return (int)uleb128_value(u) - 1; 156 | } 157 | 158 | string ULeb128Read(uleb128 &u) { 159 | local string s; 160 | s = SPrintf(s, "0x%X", uleb128_value(u)); 161 | return s; 162 | } 163 | 164 | // sleb128 165 | typedef struct { 166 | ubyte val ; 167 | if(val > 0x7f) { 168 | ubyte val ; 169 | if (val > 0x7f) { 170 | ubyte val ; 171 | if(val > 0x7f) { 172 | ubyte val ; 173 | if(val > 0x7f) { 174 | ubyte val ; 175 | } 176 | } 177 | } 178 | } 179 | } sleb128 ; 180 | 181 | // get the actual uint value of the uleb128 182 | int sleb128_value(sleb128 &u) { 183 | local int result; 184 | local ubyte cur; 185 | 186 | result = u.val[0]; 187 | if(result <= 0x7f) { 188 | result = (result << 25) >> 25; 189 | } else { 190 | cur = u.val[1]; 191 | result = (result & 0x7f) | ((uint)(cur & 0x7f) << 7); 192 | if(cur <= 0x7f) { 193 | result = (result << 18) >> 18; 194 | } else { 195 | cur = u.val[2]; 196 | result |= (uint)(cur & 0x7f) << 14; 197 | if(cur <= 0x7f) { 198 | result = (result << 11) >> 11; 199 | } else { 200 | cur = u.val[3]; 201 | result |= (uint)(cur & 0x7f) << 21; 202 | if(cur <= 0x7f) { 203 | result = (result << 4) >> 4; 204 | } else { 205 | cur = u.val[4]; 206 | result |= (uint)cur << 28; 207 | } 208 | } 209 | } 210 | } 211 | 212 | return result; 213 | } 214 | 215 | string SLeb128Read(sleb128 &u) { 216 | local string s; 217 | s = SPrintf(s, "%i", sleb128_value(u)); 218 | return s; 219 | } 220 | 221 | ////////////////////////////////////////////////// 222 | // encoded_value type 223 | ////////////////////////////////////////////////// 224 | 225 | typedef enum { 226 | VALUE_BYTE = 0x00, 227 | VALUE_SHORT = 0x02, 228 | VALUE_CHAR = 0x03, 229 | VALUE_INT = 0x04, 230 | VALUE_LONG = 0x06, 231 | VALUE_FLOAT = 0x10, 232 | VALUE_DOUBLE = 0x11, 233 | VALUE_STRING = 0x17, 234 | VALUE_TYPE = 0x18, 235 | VALUE_FIELD = 0x19, 236 | VALUE_METHOD = 0x1a, 237 | VALUE_ENUM = 0x1b, 238 | VALUE_ARRAY = 0x1c, 239 | VALUE_ANNOTATION = 0x1d, 240 | VALUE_NULL = 0x1e, 241 | VALUE_BOOLEAN = 0x1f 242 | } VALUE; 243 | 244 | // variable-width integer used by encoded_value types 245 | typedef struct (int size, VALUE type) { 246 | local int s = size + 1; 247 | local VALUE t = type; 248 | local int i; 249 | 250 | for(i=0; i; 252 | } 253 | } EncodedValue ; 254 | 255 | string EncodedValueRead(EncodedValue &v) { 256 | local string s = ""; 257 | 258 | switch(v.t) { 259 | case VALUE_BYTE: 260 | case VALUE_SHORT: 261 | case VALUE_INT: 262 | case VALUE_LONG: 263 | case VALUE_FLOAT: 264 | case VALUE_DOUBLE: 265 | SPrintf(s, "0x%X", EncodedValueValue(v)); 266 | break; 267 | case VALUE_STRING: 268 | s = StringIdRead(EncodedValueValue(v)); 269 | break; 270 | case VALUE_TYPE: 271 | s = LongTypeIdRead(EncodedValueValue(v)); 272 | break; 273 | case VALUE_FIELD: 274 | s = FieldIdRead(EncodedValueValue(v)); 275 | break; 276 | case VALUE_ENUM: 277 | s = FieldIdRead(EncodedValueValue(v)); 278 | break; 279 | case VALUE_ARRAY: 280 | case VALUE_ANNOTATION: 281 | case VALUE_BOOLEAN: 282 | case VALUE_NULL: 283 | s = "NULL"; 284 | break; 285 | } 286 | return s; 287 | } 288 | 289 | int64 EncodedValueValue(EncodedValue &v) { 290 | local int shift = 0; 291 | local int i; 292 | local int64 ret; 293 | 294 | if(v.s == 1) { 295 | return v.val; 296 | } 297 | 298 | for(i=0; i; 308 | ubyte value_arg:3 ; 309 | local string valstr = ""; 310 | local string typestr = ""; 311 | 312 | switch (value_type) { 313 | case VALUE_BYTE: 314 | ubyte value ; 315 | SPrintf(valstr, "0x%.2X", value); 316 | typestr = "byte"; 317 | break; 318 | case VALUE_SHORT: 319 | // value_arg has size-1, either 0 or 1 320 | EncodedValue value(value_arg, value_type) ; 321 | SPrintf(valstr, "%i", EncodedValueValue(value)); 322 | typestr = "short"; 323 | break; 324 | case VALUE_CHAR: 325 | EncodedValue value(value_arg, value_type) ; 326 | SPrintf(valstr, "'%c'", EncodedValueValue(value)); 327 | typestr = "char"; 328 | break; 329 | case VALUE_INT: 330 | EncodedValue value(value_arg, value_type) ; 331 | SPrintf(valstr, "%i", EncodedValueValue(value)); 332 | typestr = "int"; 333 | break; 334 | case VALUE_LONG: 335 | EncodedValue value(value_arg, value_type) ; 336 | SPrintf(valstr, "%li", EncodedValueValue(value)); 337 | typestr = "long"; 338 | break; 339 | case VALUE_FLOAT: // XXX this doesn't work 340 | EncodedValue value(value_arg, value_type) ; 341 | SPrintf(valstr, "%f", EncodedValueValue(value)); 342 | typestr = "float"; 343 | break; 344 | case VALUE_DOUBLE: 345 | EncodedValue value(value_arg, value_type) ; 346 | SPrintf(valstr, "%li", EncodedValueValue(value)); 347 | typestr = "double"; 348 | break; 349 | case VALUE_STRING: 350 | EncodedValue value(value_arg, value_type) ; 351 | valstr = "\"" + GetStringById(EncodedValueValue(value)) + "\""; 352 | typestr = "string"; 353 | break; 354 | case VALUE_TYPE: 355 | EncodedValue value(value_arg, value_type) ; 356 | valstr = GetLongTypeById(EncodedValueValue(value)); 357 | typestr = "type"; 358 | break; 359 | case VALUE_FIELD: 360 | EncodedValue value(value_arg, value_type) ; 361 | valstr = GetFieldById(EncodedValueValue(value)); 362 | typestr = "field"; 363 | break; 364 | case VALUE_METHOD: 365 | EncodedValue value(value_arg, value_type) ; 366 | valstr = GetMethodById(EncodedValueValue(value)); 367 | typestr = "method"; 368 | break; 369 | case VALUE_ENUM: 370 | EncodedValue value(value_arg, value_type) ; 371 | valstr = GetFieldById(EncodedValueValue(value)); 372 | typestr = "enum"; 373 | break; 374 | case VALUE_ARRAY: 375 | struct encoded_array array ; 376 | break; 377 | case VALUE_ANNOTATION: 378 | struct encoded_annotation annotation ; 379 | break; 380 | case VALUE_NULL: 381 | // no additional bytes used by null 382 | typestr = valstr = "NULL"; 383 | break; 384 | case VALUE_BOOLEAN: 385 | // no additional bytes used by boolean 386 | typestr = "boolean"; 387 | if(value_arg == 0) { 388 | valstr = "false"; 389 | } else { 390 | valstr = "true"; 391 | } 392 | break; 393 | default: 394 | Warning("Unknown type for encoded value 0x%X", value_type); 395 | break; 396 | } 397 | } encoded_value ; 398 | 399 | string EncodedValueStructRead(encoded_value &v) { 400 | return v.typestr + ": " + v.valstr; 401 | } 402 | 403 | typedef struct { 404 | uleb128 size ; 405 | encoded_value values[uleb128_value(size)] ; 406 | } encoded_array ; 407 | 408 | // show first 5 elements of the array 409 | string EncodedArrayRead(encoded_array &a) { 410 | local int count = 5; 411 | local int dots = 1; 412 | local int i; 413 | 414 | if(uleb128_value(a.size) < 5) { 415 | count = uleb128_value(a.size); 416 | dots = 0; 417 | } 418 | 419 | string val = "["; 420 | 421 | for(i=0; i; 439 | encoded_value value ; 440 | } annotation_element ; 441 | 442 | string AnnotationElementRead(annotation_element &e) { 443 | string name = GetStringById(uleb128_value(e.name_idx)); 444 | return name + " = " + e.value.valstr; 445 | } 446 | 447 | typedef struct { 448 | uleb128 type_idx ; 449 | uleb128 size ; 450 | 451 | if(uleb128_value(size) > 0) { 452 | annotation_element elements[uleb128_value(size)] ; 453 | } 454 | } encoded_annotation ; 455 | 456 | string EncodedAnnotationRead(encoded_annotation &a) { 457 | string s; 458 | SPrintf(s, "%i annotations for %s", uleb128_value(a.size), GetLongTypeById(uleb128_value(a.type_idx))); 459 | return s; 460 | } 461 | 462 | ////////////////////////////////////////////////// 463 | // dex file header 464 | ////////////////////////////////////////////////// 465 | 466 | typedef struct { 467 | dex_magic magic ; 468 | uint checksum ; 469 | SHA1 signature ; 470 | uint file_size ; 471 | 472 | uint header_size ; 473 | if(header_size > 0x70) { 474 | Warning("Header size appears be to larger than expected"); 475 | } 476 | 477 | uint endian_tag ; 478 | 479 | if(endian_tag != ENDIAN_CONSTANT) { 480 | // XXX we don't handle big endian files 481 | Warning("Invalid endian_tag %.8X, should be %.8X", endian_tag, ENDIAN_CONSTANT); 482 | } 483 | 484 | 485 | SetBackColor(cLtRed); 486 | uint link_size ; 487 | uint link_off ; 488 | if(link_size != 0 || link_off != 0) { 489 | Warning("A link section appears to be set, this is not supported"); 490 | } 491 | SetBackColor(cLtGreen); 492 | 493 | uint map_off ; 494 | uint string_ids_size ; 495 | uint string_ids_off ; 496 | uint type_ids_size ; 497 | uint type_ids_off ; 498 | uint proto_ids_size ; 499 | uint proto_ids_off ; 500 | uint field_ids_size ; 501 | uint field_ids_off ; 502 | uint method_ids_size ; 503 | uint method_ids_off ; 504 | uint class_defs_size ; 505 | uint class_defs_off ; 506 | uint data_size ; 507 | uint data_off ; 508 | 509 | // Anything after the rest of this, but before the other sections is essentiall 510 | // just "padding", so lets create an array variable to contain it and color it 511 | // properly 512 | if(header_size > 0x70) { 513 | SetBackColor(cLtRed); 514 | char extra_padding[header_size - 0x70]; 515 | } 516 | } header_item ; 517 | 518 | int readHeaderItemSize(header_item &item) { 519 | return ReadUInt(startof(item)+36); 520 | } 521 | 522 | ////////////////////////////////////////////////// 523 | // odex file header 524 | ////////////////////////////////////////////////// 525 | 526 | typedef enum { 527 | DEX_FLAG_VERIFIED = 0x1, 528 | DEX_OPT_FLAG_BIG = 0x2, 529 | DEX_OPT_FLAG_FIELDS = 0x4, 530 | DEX_OPT_FLAG_INVOCATIONS = 0x8 531 | } DEX_OPT_FLAGS; 532 | 533 | typedef struct { 534 | dex_magic magic ; 535 | uint dex_offset ; 536 | uint dex_length ; 537 | uint deps_offset ; 538 | uint deps_length ; 539 | uint opt_offset ; 540 | uint opt_length ; 541 | DEX_OPT_FLAGS flags ; 542 | uint checksum ; 543 | } dexopt_header_item ; 544 | 545 | string DexOptFlagsRead(DEX_OPT_FLAGS f) { 546 | string ret = ""; 547 | string flags = ""; 548 | DEX_OPT_FLAGS i = 1; 549 | 550 | while(i <= DEX_OPT_FLAG_INVOCATIONS) { 551 | if (f & i) { 552 | flags += EnumToString(i) + " "; 553 | } 554 | i = i << 1; 555 | } 556 | 557 | SPrintf(ret, "(0x%X) %s", f, flags); 558 | return ret; 559 | } 560 | 561 | ////////////////////////////////////////////////// 562 | // strings 563 | ////////////////////////////////////////////////// 564 | 565 | typedef struct { 566 | uleb128 utf16_size ; 567 | string data ; 568 | } string_item; 569 | 570 | typedef struct { 571 | uint string_data_off ; 572 | 573 | local int64 pos = FTell(); 574 | FSeek(odexpad + string_data_off); 575 | 576 | string_item string_data ; 577 | 578 | FSeek(pos); 579 | } string_id_item ; 580 | 581 | string StringDataReader(string_id_item &i) { 582 | return i.string_data.data; 583 | } 584 | 585 | typedef struct (int size) { 586 | local int s = size; 587 | string_id_item string_id[size] ; 588 | } string_id_list ; 589 | 590 | string StringIDListRead(string_id_list &l) { 591 | string s; 592 | s = SPrintf(s, "%d strings", l.s); 593 | return s; 594 | } 595 | 596 | ////////////////////////////////////////////////// 597 | // type IDs 598 | ////////////////////////////////////////////////// 599 | 600 | typedef struct { 601 | uint descriptor_idx ; 602 | } type_id_item ; 603 | 604 | string TypeIDRead(type_id_item &i) { 605 | return GetLongTypeDescriptor(GetStringById(i.descriptor_idx)); 606 | } 607 | 608 | typedef struct (int size) { 609 | local int s = size; 610 | type_id_item type_id[size] ; 611 | } type_id_list ; 612 | 613 | string TypeIDListRead(type_id_list &l) { 614 | string s; 615 | s = SPrintf(s, "%d types", l.s); 616 | return s; 617 | } 618 | 619 | ////////////////////////////////////////////////// 620 | // type list 621 | ////////////////////////////////////////////////// 622 | typedef struct { 623 | ushort type_idx ; 624 | } type_item ; 625 | 626 | typedef struct { 627 | uint size ; 628 | type_item list[size] ; 629 | } type_item_list ; 630 | 631 | string TypeItemRead(type_item &t) { 632 | return GetTypeById(t.type_idx); 633 | } 634 | 635 | string TypeItemListRead(type_item_list &l) { 636 | string s = ""; 637 | string tmp; 638 | int i; 639 | 640 | for(i = 0; i < l.size; i++) { 641 | s += GetTypeById(l.list[i].type_idx); 642 | if(i+1 < l.size) { 643 | s += ", "; 644 | } 645 | } 646 | return s; 647 | } 648 | 649 | string GetLongTypeDescriptor(string descriptor) { 650 | local string desc = ""; 651 | local string post = ""; 652 | local int i = 0; 653 | local int len = Strlen(descriptor); 654 | 655 | // array descriptors 656 | while(descriptor[i] == '[') { 657 | post += "[]"; 658 | i++; 659 | 660 | if(i >= len) return "ERROR"; 661 | } 662 | 663 | if(descriptor[i] == 'L') { 664 | // fully qualified class descriptors 665 | i++; 666 | while(i < len) { 667 | if(descriptor[i] == '/') desc += "."; 668 | else if(descriptor[i] == ';') break; 669 | else desc += descriptor[i]; 670 | i++; 671 | } 672 | } else { 673 | // simple type descriptors 674 | switch(descriptor[i]) { 675 | case 'V': desc = "void"; break; 676 | case 'Z': desc = "boolean"; break; 677 | case 'B': desc = "byte"; break; 678 | case 'S': desc = "short"; break; 679 | case 'C': desc = "char"; break; 680 | case 'I': desc = "int"; break; 681 | case 'J': desc = "long"; break; 682 | case 'F': desc = "float"; break; 683 | case 'D': desc = "double"; break; 684 | } 685 | } 686 | 687 | return desc + post; 688 | } 689 | 690 | ////////////////////////////////////////////////// 691 | // protoypes 692 | ////////////////////////////////////////////////// 693 | 694 | typedef struct { 695 | uint shorty_idx ; 696 | uint return_type_idx ; 697 | uint parameters_off ; 698 | 699 | if(parameters_off != 0) { 700 | local int64 pos = FTell(); 701 | FSeek(odexpad + parameters_off); 702 | 703 | type_item_list parameters ; 704 | 705 | FSeek(pos); 706 | } 707 | 708 | } proto_id_item ; 709 | 710 | string ProtoIDItemRead(proto_id_item &i) { 711 | return GetPrototypeSignature(i); 712 | } 713 | 714 | typedef struct (int size) { 715 | local int s = size; 716 | proto_id_item proto_id[size] ; 717 | } proto_id_list ; 718 | 719 | string ProtoIDListRead(proto_id_list &l) { 720 | string s; 721 | s = SPrintf(s, "%d prototypes", l.s); 722 | return s; 723 | } 724 | 725 | string GetParameterListString(type_item_list &l) { 726 | local string s = "("; 727 | local string tmp; 728 | local int i; 729 | 730 | for(i = 0; i < l.size; i++) { 731 | s += GetLongTypeDescriptor(GetTypeById(l.list[i].type_idx)); 732 | if(i+1 < l.size) { 733 | s += ", "; 734 | } 735 | } 736 | return s + ")"; 737 | } 738 | 739 | string GetPrototypeSignature(proto_id_item &item) { 740 | string ret = GetLongTypeDescriptor(GetTypeById(item.return_type_idx)); 741 | string params = "()"; 742 | if(exists(item.parameters)) { 743 | params = GetParameterListString(item.parameters); 744 | } 745 | 746 | return ret + " " + params; 747 | } 748 | 749 | ////////////////////////////////////////////////// 750 | // fields 751 | ////////////////////////////////////////////////// 752 | 753 | typedef struct { 754 | ushort class_idx ; 755 | ushort type_idx ; 756 | uint name_idx ; 757 | } field_id_item ; 758 | 759 | string FieldIdItemRead(field_id_item &i) { 760 | local string type = GetLongTypeDescriptor(GetTypeById(i.type_idx)); 761 | local string class = GetLongTypeDescriptor(GetTypeById(i.class_idx)); 762 | local string name = GetStringById(i.name_idx); 763 | 764 | return type + " " + class + "." + name; 765 | } 766 | 767 | typedef struct (int size) { 768 | local int s = size; 769 | field_id_item field_id[size] ; 770 | } field_id_list ; 771 | 772 | string FieldIDListRead(field_id_list &l) { 773 | string s; 774 | s = SPrintf(s, "%d fields", l.s); 775 | return s; 776 | } 777 | 778 | ////////////////////////////////////////////////// 779 | // methods 780 | ////////////////////////////////////////////////// 781 | 782 | typedef struct { 783 | ushort class_idx ; 784 | ushort proto_idx ; 785 | uint name_idx ; 786 | } method_id_item ; 787 | 788 | string ProtoIdxRead(ushort p) { 789 | string s; 790 | SPrintf(s, "(0x%X) %s", p, GetPrototypeSignature(dex_proto_ids.proto_id[p])); 791 | return s; 792 | } 793 | 794 | string MethodIdItemRead(method_id_item &m) { 795 | local string retval = GetLongTypeDescriptor(GetTypeById(dex_proto_ids.proto_id[m.proto_idx].return_type_idx)); 796 | local string classname = GetLongTypeDescriptor(GetStringById(dex_type_ids.type_id[m.class_idx].descriptor_idx)); 797 | local string methodname = GetStringById(m.name_idx); 798 | local string params = "()"; 799 | if(exists(dex_proto_ids.proto_id[m.proto_idx].parameters)) { 800 | params = GetParameterListString(dex_proto_ids.proto_id[m.proto_idx].parameters); 801 | } 802 | return retval + " " + classname + "." + methodname + params; 803 | } 804 | 805 | typedef struct (int size) { 806 | local int s = size; 807 | method_id_item method_id[size] ; 808 | } method_id_list ; 809 | 810 | string MethodIDListRead(method_id_list &l) { 811 | string s; 812 | s = SPrintf(s, "%d methods", l.s); 813 | return s; 814 | } 815 | 816 | ////////////////////////////////////////////////// 817 | // annotations 818 | ////////////////////////////////////////////////// 819 | 820 | typedef struct { 821 | uint field_idx ; 822 | uint annotations_off; 823 | 824 | if(annotations_off != 0) { 825 | local int64 pos = FTell(); 826 | FSeek(odexpad + annotations_off); 827 | 828 | struct annotation_set_item field_annotations; 829 | 830 | FSeek(pos); 831 | } 832 | } field_annotation ; 833 | 834 | string FieldAnnotationRead(field_annotation &f) { 835 | return GetFieldById(f.field_idx); 836 | } 837 | 838 | typedef struct { 839 | uint method_idx ; 840 | uint annotations_off; 841 | 842 | if(annotations_off != 0) { 843 | local int64 pos = FTell(); 844 | FSeek(odexpad + annotations_off); 845 | 846 | struct annotation_set_item method_annotations; 847 | 848 | FSeek(pos); 849 | } 850 | } method_annotation ; 851 | 852 | string MethodAnnotationRead(method_annotation &m) { 853 | return GetMethodById(m.method_idx); 854 | } 855 | 856 | typedef struct { 857 | uint method_idx ; 858 | uint annotations_off; 859 | 860 | if(annotations_off != 0) { 861 | local int64 pos = FTell(); 862 | FSeek(odexpad + annotations_off); 863 | 864 | struct annotation_set_ref_list annotations_list; 865 | 866 | FSeek(pos); 867 | } 868 | } parameter_annotation ; 869 | 870 | string ParameterAnnotationRead(parameter_annotation &p) { 871 | return GetParameterListString(dex_proto_ids.proto_id[dex_method_ids.method_id[p.method_idx].proto_idx].parameters); 872 | } 873 | 874 | typedef enum { 875 | VISIBILITY_BUILD = 0x0, 876 | VISIBILITY_RUNTIME = 0x1, 877 | VISIBILITY_SYSTEM = 0x2 878 | } VISIBILITY; 879 | 880 | typedef struct { 881 | VISIBILITY visibility ; 882 | encoded_annotation annotation ; 883 | } annotation_item ; 884 | 885 | string AnnotationItemRead(annotation_item &i) { 886 | return EncodedAnnotationRead(i.annotation); 887 | } 888 | 889 | typedef struct { 890 | uint annotation_off ; 891 | 892 | if(annotation_off != 0) { 893 | local int64 pos = FTell(); 894 | FSeek(odexpad + annotation_off); 895 | 896 | annotation_item item ; 897 | 898 | FSeek(pos); 899 | } 900 | 901 | } annotation_off_item ; 902 | 903 | string AnnotationOffItemRead(annotation_off_item &i) { 904 | if(exists(i.item)) { 905 | return AnnotationItemRead(i.item); 906 | } 907 | } 908 | 909 | typedef struct { 910 | uint size ; 911 | 912 | if(size > 0) { 913 | annotation_off_item entries[size] ; 914 | } 915 | } annotation_set_item ; 916 | 917 | string AnnotationSetItemRead(annotation_set_item &i) { 918 | local string s; 919 | SPrintf(s, "%i annotation entries", i.size); 920 | return s; 921 | } 922 | 923 | typedef struct { 924 | uint class_annotations_off ; 925 | 926 | if(class_annotations_off != 0) { 927 | local int64 pos = FTell(); 928 | FSeek(odexpad + class_annotations_off); 929 | 930 | annotation_set_item class_annotations ; 931 | 932 | FSeek(pos); 933 | } 934 | uint fields_size ; 935 | uint methods_size ; 936 | uint parameters_size ; 937 | 938 | if(fields_size > 0) { 939 | field_annotation field_annotations[fields_size] ; 940 | } 941 | 942 | if(methods_size > 0) { 943 | method_annotation method_annotations[methods_size] ; 944 | } 945 | 946 | if(parameters_size > 0) { 947 | parameter_annotation parameter_annotations[parameters_size] ; 948 | } 949 | } annotations_directory_item ; 950 | 951 | string AnnotationsDirectoryItemRead(annotations_directory_item &i) { 952 | local string s; 953 | local int classes = 0; 954 | if(exists(i.class_annotations)) { 955 | classes = i.class_annotations.size; 956 | } 957 | 958 | SPrintf(s, "%i class annotations, %i field annotations, %i method annotations, %i parameter annotations", 959 | classes, i.fields_size, i.methods_size, i.parameters_size); 960 | return s; 961 | } 962 | 963 | typedef struct { 964 | uint annotations_off ; 965 | 966 | if(annotations_off != 0) { 967 | local int64 pos = FTell(); 968 | FSeek(odexpad + annotations_off); 969 | 970 | struct annotation_set_item item ; 971 | 972 | FSeek(pos); 973 | } 974 | } annotation_set_ref_item ; 975 | 976 | typedef struct { 977 | uint size ; 978 | 979 | if(size > 0) { 980 | annotation_set_ref_item list[size] ; 981 | } 982 | } annotation_set_ref_list; 983 | 984 | ////////////////////////////////////////////////// 985 | // classes 986 | ////////////////////////////////////////////////// 987 | 988 | // access flags. some of these mean different things for different items (class/field/method) 989 | typedef enum { 990 | ACC_PUBLIC = 0x1, 991 | ACC_PRIVATE = 0x2, 992 | ACC_PROTECTED = 0x4, 993 | ACC_STATIC = 0x8, 994 | ACC_FINAL = 0x10, 995 | ACC_SYNCHRONIZED = 0x20, 996 | ACC_VOLATILE = 0x40, // field 997 | //ACC_BRIDGE = 0x40, // method 998 | ACC_TRANSIENT = 0x80, // field 999 | //ACC_VARARGS = 0x80, // method 1000 | ACC_NATIVE = 0x100, 1001 | ACC_INTERFACE = 0x200, 1002 | ACC_ABSTRACT = 0x400, 1003 | ACC_STRICT = 0x800, 1004 | ACC_SYNTHETIC = 0x1000, 1005 | ACC_ANNOTATION = 0x2000, 1006 | ACC_ENUM = 0x4000, 1007 | ACC_CONSTRUCTOR = 0x10000, 1008 | ACC_DECLARED_SYNCHRONIZED = 0x20000 1009 | } ACCESS_FLAGS ; 1010 | 1011 | string AccessFlagsRead(ACCESS_FLAGS f) { 1012 | string ret = ""; 1013 | string flags = ""; 1014 | ACCESS_FLAGS i = 1; 1015 | 1016 | while(i <= ACC_DECLARED_SYNCHRONIZED) { 1017 | if (f & i) { 1018 | flags += EnumToString(i) + " "; 1019 | } 1020 | i = i << 1; 1021 | } 1022 | 1023 | SPrintf(ret, "(0x%X) %s", f, flags); 1024 | return ret; 1025 | } 1026 | 1027 | string AccessFlagsReadUleb(uleb128 &f) { 1028 | return AccessFlagsRead(uleb128_value(f)); 1029 | } 1030 | 1031 | typedef enum { 1032 | AF_CLASS, AF_FIELD, AF_METHOD 1033 | } AF_TYPE; 1034 | 1035 | string GetFriendlyAccessFlag(int flag, AF_TYPE type) { 1036 | switch (flag) { 1037 | case ACC_PUBLIC: return "public"; 1038 | case ACC_PRIVATE: return "private"; 1039 | case ACC_PROTECTED: return "protected"; 1040 | case ACC_STATIC: return "static"; 1041 | case ACC_FINAL: return "final"; 1042 | case ACC_SYNCHRONIZED: return "synchronized"; 1043 | case ACC_VOLATILE: 1044 | if(type == AF_FIELD) return "volatile"; 1045 | else return "bridge"; // 0x40 is 'bridge' for methods 1046 | case ACC_TRANSIENT: 1047 | if(type == AF_FIELD) return "transient"; 1048 | else return "varargs"; // 0x80 is 'varargs' for methods 1049 | case ACC_NATIVE: return "native"; 1050 | case ACC_INTERFACE: return "interface"; 1051 | case ACC_ABSTRACT: return "abstract"; 1052 | case ACC_STRICT: return "strict"; 1053 | case ACC_SYNTHETIC: return "synthetic"; 1054 | case ACC_ANNOTATION: return "annotation"; 1055 | case ACC_ENUM: return "enum"; 1056 | case ACC_CONSTRUCTOR: return "constructor"; 1057 | case ACC_DECLARED_SYNCHRONIZED: return "declared-synchronized"; 1058 | } 1059 | return "ERROR"; 1060 | } 1061 | 1062 | string GetFriendlyAccessFlags(ACCESS_FLAGS f, AF_TYPE type) { 1063 | string flags = ""; 1064 | ACCESS_FLAGS i = 1; 1065 | 1066 | while(i <= ACC_DECLARED_SYNCHRONIZED) { 1067 | if (f & i) { 1068 | flags += GetFriendlyAccessFlag(i, type) + " "; 1069 | } 1070 | i = i << 1; 1071 | } 1072 | 1073 | return flags; 1074 | } 1075 | 1076 | // encoded fields 1077 | typedef struct (int previd) { 1078 | local int p = previd; 1079 | 1080 | uleb128 field_idx_diff ; 1081 | uleb128 access_flags ; 1082 | } encoded_field ; 1083 | 1084 | string EncodedFieldRead(encoded_field &f) { 1085 | local int realid = f.p + uleb128_value(f.field_idx_diff); 1086 | return GetFriendlyAccessFlags(uleb128_value(f.access_flags), AF_FIELD) + GetFieldById(realid); 1087 | } 1088 | 1089 | typedef struct (int size) { 1090 | local int s = size; 1091 | local int i; 1092 | local int fieldid = 0; 1093 | 1094 | for(i=0; i; 1096 | fieldid = fieldid + uleb128_value(field.field_idx_diff); 1097 | } 1098 | } encoded_field_list ; 1099 | 1100 | string EncodedFieldListRead(encoded_field_list &l) { 1101 | local string s; 1102 | SPrintf(s, "%i fields", l.s); 1103 | return s; 1104 | } 1105 | 1106 | // encoded methods 1107 | typedef struct (int previd) { 1108 | local int p = previd; 1109 | 1110 | uleb128 method_idx_diff ; 1111 | uleb128 access_flags ; 1112 | uleb128 code_off ; 1113 | 1114 | if(uleb128_value(code_off) != 0) { 1115 | local int64 pos = FTell(); 1116 | FSeek(odexpad + uleb128_value(code_off)); 1117 | struct code_item code ; 1118 | FSeek(pos); 1119 | } 1120 | } encoded_method ; 1121 | 1122 | string EncodedMethodRead(encoded_method &m) { 1123 | local int realid = m.p + uleb128_value(m.method_idx_diff); 1124 | return GetFriendlyAccessFlags(uleb128_value(m.access_flags), AF_METHOD) + GetMethodById(realid); 1125 | } 1126 | 1127 | typedef struct (int size) { 1128 | local int s = size; 1129 | local int i; 1130 | local int methodid = 0; 1131 | 1132 | for(i=0; i; 1134 | methodid = methodid + uleb128_value(method.method_idx_diff); 1135 | } 1136 | } encoded_method_list ; 1137 | 1138 | string EncodedMethodListRead(encoded_method_list &l) { 1139 | local string s; 1140 | SPrintf(s, "%i methods", l.s); 1141 | return s; 1142 | } 1143 | 1144 | typedef struct { 1145 | uleb128 static_fields_size ; 1146 | uleb128 instance_fields_size ; 1147 | uleb128 direct_methods_size ; 1148 | uleb128 virtual_methods_size ; 1149 | 1150 | if(uleb128_value(static_fields_size) > 0) { 1151 | encoded_field_list static_fields(uleb128_value(static_fields_size)) ; 1152 | } 1153 | 1154 | if(uleb128_value(instance_fields_size) > 0) { 1155 | encoded_field_list instance_fields(uleb128_value(instance_fields_size)) ; 1156 | } 1157 | 1158 | if(uleb128_value(direct_methods_size) > 0) { 1159 | encoded_method_list direct_methods(uleb128_value(direct_methods_size)) ; 1160 | } 1161 | 1162 | if(uleb128_value(virtual_methods_size) > 0) { 1163 | encoded_method_list virtual_methods(uleb128_value(virtual_methods_size)) ; 1164 | } 1165 | } class_data_item ; 1166 | 1167 | string ClassDataItemRead(class_data_item &i) { 1168 | local string s; 1169 | SPrintf(s, "%i static fields, %i instance fields, %i direct methods, %i virtual methods", 1170 | uleb128_value(i.static_fields_size), uleb128_value(i.instance_fields_size), 1171 | uleb128_value(i.direct_methods_size), uleb128_value(i.virtual_methods_size)); 1172 | return s; 1173 | } 1174 | 1175 | typedef struct { 1176 | local int64 pos; 1177 | 1178 | uint class_idx ; 1179 | ACCESS_FLAGS access_flags ; 1180 | uint superclass_idx ; 1181 | 1182 | uint interfaces_off ; 1183 | if(interfaces_off != 0) { 1184 | pos = FTell(); 1185 | FSeek(odexpad + interfaces_off); 1186 | type_item_list interfaces ; 1187 | FSeek(pos); 1188 | } 1189 | 1190 | uint source_file_idx ; 1191 | 1192 | uint annotations_off ; 1193 | if(annotations_off != 0) { 1194 | pos = FTell(); 1195 | FSeek(odexpad + annotations_off); 1196 | annotations_directory_item annotations ; 1197 | FSeek(pos); 1198 | } 1199 | 1200 | uint class_data_off ; 1201 | if(class_data_off != 0) { 1202 | pos = FTell(); 1203 | FSeek(odexpad + class_data_off); 1204 | class_data_item class_data ; 1205 | FSeek(pos); 1206 | } 1207 | 1208 | uint static_values_off ; 1209 | if(static_values_off != 0) { 1210 | pos = FTell(); 1211 | FSeek(odexpad + static_values_off); 1212 | struct encoded_array_item static_values ; 1213 | FSeek(pos); 1214 | } 1215 | } class_def_item ; 1216 | 1217 | string ClassDefItemRead(class_def_item &i) { 1218 | local string classname = GetLongTypeById(i.class_idx); 1219 | local string flags = GetFriendlyAccessFlags(i.access_flags, AF_CLASS); 1220 | return flags + classname; 1221 | } 1222 | 1223 | string InterfacesRead(type_item_list &l) { 1224 | string s = ""; 1225 | int i; 1226 | 1227 | for(i = 0; i < l.size; i++) { 1228 | s += GetLongTypeDescriptor(GetTypeById(l.list[i].type_idx)); 1229 | if(i+1 < l.size) { 1230 | s += ", "; 1231 | } 1232 | } 1233 | return s; 1234 | } 1235 | 1236 | typedef struct (int size) { 1237 | local int s = size; 1238 | class_def_item class_def[size] ; 1239 | } class_def_item_list ; 1240 | 1241 | string ClassDefItemListRead(class_def_item_list &l) { 1242 | string s; 1243 | s = SPrintf(s, "%d classes", l.s); 1244 | return s; 1245 | } 1246 | 1247 | typedef struct { 1248 | uint start_addr ; 1249 | ushort insn_count ; 1250 | ushort handler_off ; 1251 | } try_item ; 1252 | 1253 | typedef struct { 1254 | sleb128 size ; 1255 | 1256 | local int s = sleb128_value(size); 1257 | local int numhandlers = 0; 1258 | 1259 | if(s != 0) { 1260 | numhandlers = Abs(s); 1261 | struct encoded_type_addr_pair handlers[numhandlers] ; 1262 | } 1263 | 1264 | if(s <= 0) { 1265 | uleb128 catch_all_addr ; 1266 | numhandlers++; 1267 | } 1268 | } encoded_catch_handler ; 1269 | 1270 | string EncodedCatchHandlerRead(encoded_catch_handler &h) { 1271 | local string s; 1272 | SPrintf(s, "%i handlers", h.numhandlers); 1273 | return s; 1274 | } 1275 | 1276 | typedef struct { 1277 | uleb128 size ; 1278 | encoded_catch_handler list[uleb128_value(size)] ; 1279 | } encoded_catch_handler_list ; 1280 | 1281 | string EncodedCatchHandlerListRead(encoded_catch_handler_list &l) { 1282 | local string s; 1283 | SPrintf(s, "%i handler lists", uleb128_value(l.size)); 1284 | return s; 1285 | } 1286 | 1287 | typedef struct { 1288 | ushort registers_size ; 1289 | ushort ins_size ; 1290 | ushort outs_size ; 1291 | ushort tries_size ; 1292 | uint debug_info_off ; 1293 | 1294 | if(debug_info_off != 0) { 1295 | local int64 pos = FTell(); 1296 | FSeek(odexpad + debug_info_off); 1297 | 1298 | struct debug_info_item debug_info ; 1299 | FSeek(pos); 1300 | } 1301 | 1302 | uint insns_size ; 1303 | if(insns_size != 0) { 1304 | ushort insns[insns_size] ; 1305 | } 1306 | 1307 | if(tries_size != 0) { 1308 | if (insns_size & 1 == 1) { 1309 | ushort padding ; 1310 | } 1311 | 1312 | try_item tries[tries_size] ; 1313 | encoded_catch_handler_list handlers ; 1314 | } 1315 | } code_item ; 1316 | 1317 | string CodeItemRead(code_item &i) { 1318 | local string s; 1319 | SPrintf(s, "%i registers, %i in arguments, %i out arguments, %i tries, %i instructions", 1320 | i.registers_size, i.ins_size, i.outs_size, i.tries_size, i.insns_size); 1321 | return s; 1322 | } 1323 | 1324 | typedef struct { 1325 | uleb128 type_idx ; 1326 | uleb128 addr ; 1327 | } encoded_type_addr_pair ; 1328 | 1329 | string EncodedTypeAddrPairRead(encoded_type_addr_pair &p) { 1330 | string s; 1331 | SPrintf(s, "%s at 0x%X", GetLongTypeById(uleb128_value(p.type_idx)), uleb128_value(p.addr)); 1332 | return s; 1333 | } 1334 | 1335 | typedef struct { 1336 | encoded_array value ; 1337 | } encoded_array_item ; 1338 | 1339 | string EncodedArrayItemRead(encoded_array_item &i) { 1340 | local string s; 1341 | SPrintf(s, "%i items: %s", uleb128_value(i.value.size), EncodedArrayRead(i.value)); 1342 | return s; 1343 | } 1344 | 1345 | enum TYPE_CODES { 1346 | TYPE_HEADER_ITEM = 0x0000, 1347 | TYPE_STRING_ID_ITEM = 0x0001, 1348 | TYPE_TYPE_ID_ITEM = 0x0002, 1349 | TYPE_PROTO_ID_ITEM = 0x0003, 1350 | TYPE_FIELD_ID_ITEM = 0x0004, 1351 | TYPE_METHOD_ID_ITEM = 0x0005, 1352 | TYPE_CLASS_DEF_ITEM = 0x0006, 1353 | 1354 | TYPE_MAP_LIST = 0x1000, 1355 | TYPE_TYPE_LIST = 0x1001, 1356 | TYPE_ANNOTATION_SET_REF_LIST = 0x1002, 1357 | TYPE_ANNOTATION_SET_ITEM = 0x1003, 1358 | 1359 | TYPE_CLASS_DATA_ITEM = 0x2000, 1360 | TYPE_CODE_ITEM = 0x2001, 1361 | TYPE_STRING_DATA_ITEM = 0x2002, 1362 | TYPE_DEBUG_INFO_ITEM = 0x2003, 1363 | TYPE_ANNOTATION_ITEM = 0x2004, 1364 | TYPE_ENCODED_ARRAY_ITEM = 0x2005, 1365 | TYPE_ANNOTATIONS_DIRECTORY_ITEM = 0x2006 1366 | }; 1367 | 1368 | ////////////////////////////////////////////////// 1369 | // debug info 1370 | ////////////////////////////////////////////////// 1371 | 1372 | typedef enum { 1373 | DBG_END_SEQUENCE = 0x00, 1374 | DBG_ADVANCE_PC = 0x01, 1375 | DBG_ADVANCE_LINE = 0x02, 1376 | DBG_START_LOCAL = 0x03, 1377 | DBG_START_LOCAL_EXTENDED = 0x04, 1378 | DBG_END_LOCAL = 0x05, 1379 | DBG_RESTART_LOCAL = 0x06, 1380 | DBG_SET_PROLOGUE_END = 0x07, 1381 | DBG_SET_EPILOGUE_BEGIN = 0x08, 1382 | DBG_SET_FILE = 0x09 1383 | } DBG_OPCODE; 1384 | 1385 | typedef struct { 1386 | DBG_OPCODE opcode ; 1387 | local string args = ""; 1388 | 1389 | switch (opcode) { 1390 | case DBG_END_SEQUENCE: 1391 | break; 1392 | case DBG_ADVANCE_PC: 1393 | uleb128 addr_diff ; 1394 | SPrintf(args, "%i", uleb128_value(addr_diff)); 1395 | break; 1396 | case DBG_ADVANCE_LINE: 1397 | sleb128 line_diff ; 1398 | SPrintf(args, "%i", sleb128_value(line_diff)); 1399 | break; 1400 | case DBG_START_LOCAL: 1401 | uleb128 register_num ; 1402 | uleb128p1 name_idx ; 1403 | uleb128p1 type_idx ; 1404 | SPrintf(args, "%i, %s, %s", uleb128_value(register_num), StringIdReadUlebp1(name_idx), 1405 | LongTypeIdReadUlebp1(type_idx)); 1406 | break; 1407 | case DBG_START_LOCAL_EXTENDED: 1408 | uleb128 register_num ; 1409 | uleb128p1 name_idx ; 1410 | uleb128p1 type_idx ; 1411 | uleb128p1 sig_idx ; 1412 | SPrintf(args, "%i, %s, %s, %s", uleb128_value(register_num), StringIdReadUlebp1(name_idx), 1413 | LongTypeIdReadUlebp1(type_idx), StringIdReadUlebp1(sig_idx)); 1414 | break; 1415 | case DBG_END_LOCAL: 1416 | uleb128 register_num ; 1417 | SPrintf(args, "%i", uleb128_value(register_num)); 1418 | break; 1419 | case DBG_RESTART_LOCAL: 1420 | uleb128 register_num ; 1421 | SPrintf(args, "%i", uleb128_value(register_num)); 1422 | break; 1423 | case DBG_SET_PROLOGUE_END: 1424 | case DBG_SET_EPILOGUE_BEGIN: 1425 | break; 1426 | case DBG_SET_FILE: 1427 | uleb128p1 name_idx ; 1428 | SPrintf(args, "%s", StringIdReadUlebp1(name_idx)); 1429 | } 1430 | } debug_opcode ; 1431 | 1432 | #define DBG_FIRST_SPECIAL 0x0a 1433 | #define DBG_LINE_BASE -4 1434 | #define DBG_LINE_RANGE 15 1435 | 1436 | string DebugOpcodeRead(debug_opcode &opcode) { 1437 | local string s; 1438 | if(opcode.opcode >= DBG_FIRST_SPECIAL) { 1439 | local ubyte adjusted = opcode.opcode - DBG_FIRST_SPECIAL; 1440 | SPrintf(s, "Special opcode: line + %i, address + %i", DBG_LINE_BASE + (adjusted % DBG_LINE_RANGE), (adjusted / DBG_LINE_RANGE)); 1441 | } else { 1442 | s = EnumToString(opcode.opcode); 1443 | } 1444 | 1445 | if(opcode.args != "") { 1446 | s += " (" + opcode.args + ")"; 1447 | } 1448 | 1449 | return s; 1450 | } 1451 | 1452 | typedef struct { 1453 | uleb128 line_start ; 1454 | uleb128 parameters_size ; 1455 | if(uleb128_value(parameters_size) > 0) { 1456 | uleb128p1 parameter_names[uleb128_value(parameters_size)] ; // actually uleb128p1 1457 | } 1458 | 1459 | do { 1460 | debug_opcode opcode ; 1461 | } while (opcode.opcode != DBG_END_SEQUENCE); 1462 | } debug_info_item; 1463 | 1464 | ////////////////////////////////////////////////// 1465 | // map list 1466 | ////////////////////////////////////////////////// 1467 | typedef struct { 1468 | TYPE_CODES type; 1469 | ushort unused; 1470 | uint size; 1471 | uint offset; 1472 | } map_item ; 1473 | 1474 | string MapItemRead(map_item &m) { 1475 | string s; 1476 | SPrintf(s, "%s", EnumToString(m.type)); 1477 | return s; 1478 | } 1479 | 1480 | typedef struct { 1481 | uint size; 1482 | map_item list[size]; 1483 | } map_list_type ; 1484 | 1485 | string MapListTypeRead(map_list_type &t) { 1486 | local string s; 1487 | SPrintf(s, "%i items", t.size); 1488 | return s; 1489 | } 1490 | 1491 | ////////////////////////////////////////////////// 1492 | // utility functions for reading various strings 1493 | // note: strings are stored in a format called MUTF-8, and its 1494 | // possible they won't always display correctly in the 010 UI 1495 | ////////////////////////////////////////////////// 1496 | 1497 | // read a value from the string table 1498 | string StringIdRead(int id) { 1499 | if(id == NO_INDEX) { 1500 | return "NO_INDEX"; 1501 | } 1502 | 1503 | local string s; 1504 | SPrintf(s, "(0x%.X) \"%s\"", id, GetStringById(id)); 1505 | return s; 1506 | } 1507 | 1508 | string StringIdReadUleb(uleb128 &id) { 1509 | return StringIdRead(uleb128_value(id)); 1510 | } 1511 | 1512 | string StringIdReadUlebp1(uleb128p1 &id) { 1513 | return StringIdRead(uleb128p1_value(id)); 1514 | } 1515 | 1516 | // read a value from the type table, return short form 1517 | string TypeIdRead(int id) { 1518 | return GetIdAndNameString(id, GetTypeById(id)); 1519 | } 1520 | 1521 | // read a value from the type table, return the long form 1522 | string LongTypeIdRead(int id) { 1523 | return GetIdAndNameString(id, GetLongTypeById(id)); 1524 | } 1525 | 1526 | string LongTypeIdReadUleb(uleb128 &id) { 1527 | return LongTypeIdRead(uleb128_value(id)); 1528 | } 1529 | 1530 | string LongTypeIdReadUlebp1(uleb128p1 &id) { 1531 | return LongTypeIdRead(uleb128p1_value(id)); 1532 | } 1533 | 1534 | string FieldIdRead(int id) { 1535 | return GetIdAndNameString(id, GetFieldById(id)); 1536 | } 1537 | 1538 | string MethodIdRead(int id) { 1539 | return GetIdAndNameString(id, GetMethodById(id)); 1540 | } 1541 | 1542 | string GetIdAndNameString(int id, string name) { 1543 | local string s; 1544 | SPrintf(s, "(0x%X) %s", id, name); 1545 | return s; 1546 | } 1547 | 1548 | // read a string from the string table 1549 | string GetStringById(int id) { 1550 | if(id == NO_INDEX) { 1551 | return "NO_INDEX"; 1552 | } 1553 | 1554 | if(exists(dex_string_ids.string_id[id])) { 1555 | return dex_string_ids.string_id[id].string_data.data; 1556 | } else { 1557 | return "*** NO STRING"; 1558 | } 1559 | } 1560 | 1561 | string GetTypeById(int id) { 1562 | if(id == NO_INDEX) { 1563 | return "NO_INDEX"; 1564 | } 1565 | 1566 | if(exists(dex_type_ids.type_id[id])) { 1567 | return GetStringById(dex_type_ids.type_id[id].descriptor_idx); 1568 | } else { 1569 | return "*** NO TYPE"; 1570 | } 1571 | } 1572 | 1573 | string GetLongTypeById(int id) { 1574 | return GetLongTypeDescriptor(GetTypeById(id)); 1575 | } 1576 | 1577 | string GetMethodById(int id) { 1578 | if(id == NO_INDEX) { 1579 | return "NO_INDEX"; 1580 | } 1581 | 1582 | if(exists(dex_method_ids.method_id[id])) { 1583 | return MethodIdItemRead(dex_method_ids.method_id[id]); 1584 | } else { 1585 | return "*** NO METHOD"; 1586 | } 1587 | } 1588 | 1589 | string GetFieldById(int id) { 1590 | if(id == NO_INDEX) { 1591 | return "NO_INDEX"; 1592 | } 1593 | 1594 | if(exists(dex_field_ids.field_id[id])) { 1595 | return FieldIdItemRead(dex_field_ids.field_id[id]); 1596 | } else { 1597 | return "*** NO FIELD"; 1598 | } 1599 | } 1600 | 1601 | ////////////////////////////////////////////////// 1602 | // dexopt stuff 1603 | ////////////////////////////////////////////////// 1604 | 1605 | typedef enum { 1606 | DEX_CHUNK_CLASS_LOOKUP = 0x434c4b50, 1607 | DEX_CHUNK_REGISTER_MAPS = 0x524d4150, 1608 | DEX_CHUNK_END = 0x41454e44 1609 | } DEX_CHUNK_TYPE; 1610 | 1611 | typedef struct { 1612 | DEX_CHUNK_TYPE type ; 1613 | uint size ; 1614 | local int realsize = (size + 7) & ~7; 1615 | 1616 | 1617 | if(type == DEX_CHUNK_CLASS_LOOKUP) { 1618 | struct dex_class_lookup class_lookup_table ; 1619 | } else if (type == DEX_CHUNK_REGISTER_MAPS) { 1620 | ubyte chunkbytes[realsize]; 1621 | } else if (type == DEX_CHUNK_END) { 1622 | //ubyte chunkbytes[realsize]; 1623 | } else { 1624 | Warning("Unknown chunk type 0x%X", type); 1625 | return; 1626 | } 1627 | } dexopt_opt_chunk ; 1628 | 1629 | typedef struct { 1630 | local int count = 0; 1631 | do { 1632 | dexopt_opt_chunk chunk; 1633 | count++; 1634 | } while(chunk.type != DEX_CHUNK_END); 1635 | } dexopt_opt_table ; 1636 | 1637 | string DexoptOptTableRead(dexopt_opt_table &t) { 1638 | local string s; 1639 | SPrintf(s, "%i items", t.count); 1640 | return s; 1641 | } 1642 | 1643 | string DexOptChunkRead(dexopt_opt_chunk &c) { 1644 | local string s; 1645 | SPrintf(s, "%s chunk: %i bytes", EnumToString(c.type), c.size); 1646 | return s; 1647 | } 1648 | 1649 | typedef struct { 1650 | uint class_descriptor_hash ; 1651 | int class_descriptor_offset ; 1652 | int class_definition_offset ; 1653 | } dex_class_lookup_entry ; 1654 | 1655 | string DexClassLookupEntryRead(dex_class_lookup_entry &e) { 1656 | local string s; 1657 | SPrintf(s, "0x%X: (descriptor 0x%X, definition 0x%X)", e.class_descriptor_hash, e.class_descriptor_offset, e.class_definition_offset); 1658 | return s; 1659 | } 1660 | 1661 | typedef struct { 1662 | int size ; 1663 | int num_entries ; 1664 | 1665 | if(num_entries > 0) { 1666 | dex_class_lookup_entry table[num_entries] ; 1667 | } 1668 | } dex_class_lookup; 1669 | 1670 | ////////////////////////////////////////////////// 1671 | // main stuff 1672 | ////////////////////////////////////////////////// 1673 | 1674 | // first check file type - dex files start with 'dex', odex files start with 'dey' 1675 | local int odex = 0; 1676 | local char tmp[3]; 1677 | ReadBytes(tmp, 0, 3); 1678 | FSeek(0); 1679 | 1680 | if(!Strcmp(tmp, "dey")) { 1681 | odex = 1; 1682 | } 1683 | 1684 | // dexopt files start with a dexopt header 1685 | if(odex) { 1686 | dexopt_header_item dexopt_header ; 1687 | odexpad = dexopt_header.dex_offset; 1688 | FSeek(odexpad); 1689 | } 1690 | 1691 | // main dex header and structs 1692 | 1693 | SetBackColor(cLtGreen); 1694 | header_item dex_header ; 1695 | 1696 | FSeek(dex_header.string_ids_off); 1697 | SetBackColor(cLtYellow); 1698 | string_id_list dex_string_ids(dex_header.string_ids_size) ; 1699 | 1700 | FSeek(dex_header.type_ids_off); 1701 | SetBackColor(cLtPurple); 1702 | type_id_list dex_type_ids(dex_header.type_ids_size) ; 1703 | 1704 | FSeek(dex_header.proto_ids_off); 1705 | SetBackColor(cLtBlue); 1706 | proto_id_list dex_proto_ids(dex_header.proto_ids_size) ; 1707 | 1708 | FSeek(dex_header.field_ids_off); 1709 | SetBackColor(cYellow); 1710 | field_id_list dex_field_ids(dex_header.field_ids_size) ; 1711 | 1712 | FSeek(dex_header.method_ids_off); 1713 | SetBackColor(cDkYellow); 1714 | method_id_list dex_method_ids(dex_header.method_ids_size) ; 1715 | 1716 | FSeek(dex_header.class_defs_off); 1717 | SetBackColor(cLtGray); 1718 | class_def_item_list dex_class_defs(dex_header.class_defs_size) ; 1719 | 1720 | // map list, we don't really do anything with it though 1721 | SetBackColor(cLtAqua); 1722 | if(dex_header.map_off != 0) { 1723 | FSeek(odexpad + dex_header.map_off); 1724 | map_list_type dex_map_list ; 1725 | } 1726 | 1727 | if(odex) { 1728 | if(dexopt_header.deps_offset != 0) { 1729 | FSeek(dexopt_header.deps_offset); 1730 | ubyte dexopt_deps[dexopt_header.deps_length] ; 1731 | } 1732 | 1733 | if(dexopt_header.opt_offset != 0) { 1734 | FSeek(dexopt_header.opt_offset); 1735 | dexopt_opt_table opt_table ; 1736 | } 1737 | } -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a repository for random scripts and files that I use for Android reversing. 2 | 3 | Files: 4 | 5 | DEXTemplate.bt - a DEX file parsing template for the 010 hex editor (http://www.sweetscape.com/010editor) 6 | smali.vim - VIM syntax highlighting for smali files 7 | 8 | -------------------------------------------------------------------------------- /smali.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: Smali (Dalvik) Assembly 3 | " Maintainer: Jon Larimer 4 | " Last change: 2010 Jan 8 5 | " 6 | " Syntax highlighting for baksmali (Dalvik disassembler) output 7 | 8 | " For version 5.x: Clear all syntax items 9 | " For version 6.x: Quit when a syntax file was already loaded 10 | if version < 600 11 | syntax clear 12 | elseif exists("b:current_syntax") 13 | finish 14 | endif 15 | 16 | setlocal iskeyword=@,48-57,_,128-167,224-235,.,-,/ 17 | 18 | syn region dalvikComment start="#" keepend end="$" 19 | 20 | " directives 21 | syn keyword dalvikDirective .class .super .implements .field 22 | syn keyword dalvikDirective .subannotation .annotation 23 | syn keyword dalvikDirective .enum .method .registers .locals .array-data 24 | syn keyword dalvikDirective .packed-switch 25 | syn keyword dalvikDirective .sparse-switch .catch .catchall .line 26 | syn keyword dalvikDirective .parameter .local 27 | syn keyword dalvikDirective .prologue .epilogue 28 | syn keyword dalvikDirective .source 29 | syn match dalvikDirective /\.end\s\+\(field\|subannotation\|annotation\|method\|array-data\)/ 30 | syn match dalvikDirective /\.end\s\+\(packed-switch\|sparse-switch\|parameter\|local\)/ 31 | syn match dalvikDirective /\.restart\s+local/ 32 | 33 | " access modifiers 34 | syn keyword dalvikAccess public private protected static final synchronized bridge varargs 35 | syn keyword dalvikAccess native abstract strictfp synthetic constructor declared-synchronized 36 | syn keyword dalvikAccess interface enum annotation volatile transient 37 | 38 | " instructions 39 | syn keyword dalvikInstruction goto return-void nop const/4 move-result move-result-wide 40 | syn keyword dalvikInstruction move-result-object move-exception return return-wide 41 | syn keyword dalvikInstruction return-object monitor-enter monitor-exit throw move 42 | syn keyword dalvikInstruction move-wide move-object array-length neg-int not-int neg-long 43 | syn keyword dalvikInstruction not-long neg-float neg-double int-to-long int-to-float 44 | syn keyword dalvikInstruction int-to-double long-to-int long-to-float long-to-double 45 | syn keyword dalvikInstruction float-to-int float-to-long float-to-double double-to-int 46 | syn keyword dalvikInstruction double-to-long double-to-float int-to-byte int-to-char 47 | syn keyword dalvikInstruction int-to-short add-int/2addr sub-int/2addr mul-int/2addr 48 | syn keyword dalvikInstruction div-int/2addr rem-int/2addr and-int/2addr or-int/2addr 49 | syn keyword dalvikInstruction xor-int/2addr shl-int/2addr shr-int/2addr ushr-int/2addr 50 | syn keyword dalvikInstruction add-long/2addr sub-long/2addr mul-long/2addr div-long/2addr 51 | syn keyword dalvikInstruction rem-long/2addr and-long/2addr or-long/2addr xor-long/2addr 52 | syn keyword dalvikInstruction shl-long/2addr shr-long/2addr ushr-long/2addr add-float/2addr 53 | syn keyword dalvikInstruction sub-float/2addr mul-float/2addr div-float/2addr rem-float/2addr 54 | syn keyword dalvikInstruction add-double/2addr sub-double/2addr mul-double/2addr 55 | syn keyword dalvikInstruction div-double/2addr rem-double/2addr goto/16 sget sget-wide 56 | syn keyword dalvikInstruction sget-object sget-boolean sget-byte sget-char sget-short sput 57 | syn keyword dalvikInstruction sput-wide sput-object sput-boolean sput-byte sput-char sput-short 58 | syn keyword dalvikInstruction const-string check-cast new-instance const-class const/high16 59 | syn keyword dalvikInstruction const-wide/high16 const/16 const-wide/16 if-eqz if-nez if-ltz 60 | syn keyword dalvikInstruction if-gez if-gtz if-lez add-int/lit8 rsub-int/lit8 mul-int/lit8 61 | syn keyword dalvikInstruction div-int/lit8 rem-int/lit8 and-int/lit8 or-int/lit8 xor-int/lit8 62 | syn keyword dalvikInstruction shl-int/lit8 shr-int/lit8 ushr-int/lit8 iget iget-wide iget-object 63 | syn keyword dalvikInstruction iget-boolean iget-byte iget-char iget-short iput iput-wide iput-object 64 | syn keyword dalvikInstruction iput-boolean iput-byte iput-char iput-short instance-of new-array 65 | syn keyword dalvikInstruction iget-quick iget-wide-quick iget-object-quick iput-quick 66 | syn keyword dalvikInstruction iput-wide-quick iput-object-quick rsub-int add-int/lit16 mul-int/lit16 67 | syn keyword dalvikInstruction div-int/lit16 rem-int/lit16 and-int/lit16 or-int/lit16 xor-int/lit16 68 | syn keyword dalvikInstruction if-eq if-ne if-lt if-ge if-gt if-le move/from16 move-wide/from16 69 | syn keyword dalvikInstruction move-object/from16 cmpl-float cmpg-float cmpl-double cmpg-double 70 | syn keyword dalvikInstruction cmp-long aget aget-wide aget-object aget-boolean aget-byte aget-char 71 | syn keyword dalvikInstruction aget-short aput aput-wide aput-object aput-boolean aput-byte aput-char 72 | syn keyword dalvikInstruction aput-short add-int sub-int mul-int div-int rem-int and-int or-int 73 | syn keyword dalvikInstruction xor-int shl-int shr-int ushr-int add-long sub-long mul-long div-long 74 | syn keyword dalvikInstruction rem-long and-long or-long xor-long shl-long shr-long ushr-long 75 | syn keyword dalvikInstruction add-float sub-float mul-float div-float rem-float add-double 76 | syn keyword dalvikInstruction sub-double mul-double div-double rem-double goto/32 const-string/jumbo 77 | syn keyword dalvikInstruction const const-wide/32 fill-array-data packed-switch sparse-switch move/16 78 | syn keyword dalvikInstruction move-wide/16 move-object/16 invoke-virtual invoke-super invoke-direct 79 | syn keyword dalvikInstruction invoke-static invoke-interface filled-new-array invoke-direct-empty 80 | syn keyword dalvikInstruction execute-inline invoke-virtual-quick invoke-super-quick 81 | syn keyword dalvikInstruction invoke-virtual/range invoke-super/range invoke-direct/range 82 | syn keyword dalvikInstruction invoke-static/range invoke-interface/range filled-new-array/range 83 | syn keyword dalvikInstruction invoke-virtual-quick/range invoke-super-quick/range const-wide 84 | 85 | " class names (between L and ;) 86 | syn region dalvikName matchgroup=dalvikNameWrapper start="L" end=";" oneline 87 | syn region dalvikString start=+"+ end=+"+ 88 | 89 | " branch labels 90 | syn match dalvikLabel "\<[A-Za-z0-9_]\+\>:$" 91 | 92 | " registers 93 | syn match dalvikRegister "\<[vp]\d\+\>" 94 | 95 | " number literals 96 | syn match dalvikNumber "\<\-\?\(0[0-7]*\|0[xX]\x\+\|\d\+\)[lLst]\=\>" 97 | syn match dalvikNumber "\(\<\d\+\.\d*\|\.\d\+\)\([eE][-+]\=\d\+\)\=[fFdD]\=" 98 | syn match dalvikNumber "\<\d\+[eE][-+]\=\d\+[fFdD]\=\>" 99 | syn match dalvikNumber "\<\d\+\([eE][-+]\=\d\+\)\=[fFdD]\>" 100 | 101 | " default colors (for background=dark): 102 | " Comment/Identifier = cyan 103 | " Constant = magenta 104 | " Special = lightred 105 | " Identifier = cyan 106 | " Statement = yellow 107 | " PreProc = lightblue 108 | " Type = lightgreen 109 | 110 | hi def link dalvikDirective PreProc 111 | hi def link dalvikAccess Statement 112 | hi def link dalvikComment Comment 113 | hi def link dalvikName Constant 114 | "hi def link dalvikNameWrapper Special 115 | hi def link dalvikNumber Constant 116 | hi def link dalvikString Constant 117 | hi def link dalvikLabel Statement 118 | hi def link dalvikRegister Special 119 | hi def link dalvikInstruction Type 120 | 121 | let b:current_syntax = "smali" 122 | 123 | --------------------------------------------------------------------------------