Home | History | Annotate | Download | only in raw
      1 /*
      2  * Copyright 2013, Google Inc.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 package org.jf.dexlib2.dexbacked.raw;
     33 
     34 import org.jf.dexlib2.dexbacked.BaseDexBuffer;
     35 import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator;
     36 import org.jf.dexlib2.util.AnnotatedBytes;
     37 import org.jf.util.StringUtils;
     38 
     39 import javax.annotation.Nonnull;
     40 import javax.annotation.Nullable;
     41 
     42 public class HeaderItem {
     43     public static final int ITEM_SIZE = 0x70;
     44 
     45     /**
     46      * The magic numbers for dex files.
     47      *
     48      * They are: "dex\n035\0" and "dex\n037\0".
     49      */
     50     public static final byte[][] MAGIC_VALUES= new byte[][] {
     51             new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00},
     52             new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x37, 0x00}};
     53 
     54     public static final int LITTLE_ENDIAN_TAG = 0x12345678;
     55     public static final int BIG_ENDIAN_TAG = 0x78563412;
     56 
     57     public static final int CHECKSUM_OFFSET = 8;
     58 
     59     // this is the start of the checksumed data
     60     public static final int CHECKSUM_DATA_START_OFFSET = 12;
     61     public static final int SIGNATURE_OFFSET = 12;
     62     public static final int SIGNATURE_SIZE = 20;
     63 
     64     // this is the start of the sha-1 hashed data
     65     public static final int SIGNATURE_DATA_START_OFFSET = 32;
     66     public static final int FILE_SIZE_OFFSET = 32;
     67 
     68     public static final int HEADER_SIZE_OFFSET = 36;
     69 
     70     public static final int ENDIAN_TAG_OFFSET = 40;
     71 
     72     public static final int MAP_OFFSET = 52;
     73 
     74     public static final int STRING_COUNT_OFFSET = 56;
     75     public static final int STRING_START_OFFSET = 60;
     76 
     77     public static final int TYPE_COUNT_OFFSET = 64;
     78     public static final int TYPE_START_OFFSET = 68;
     79 
     80     public static final int PROTO_COUNT_OFFSET = 72;
     81     public static final int PROTO_START_OFFSET = 76;
     82 
     83     public static final int FIELD_COUNT_OFFSET = 80;
     84     public static final int FIELD_START_OFFSET = 84;
     85 
     86     public static final int METHOD_COUNT_OFFSET = 88;
     87     public static final int METHOD_START_OFFSET = 92;
     88 
     89     public static final int CLASS_COUNT_OFFSET = 96;
     90     public static final int CLASS_START_OFFSET = 100;
     91 
     92     @Nonnull private RawDexFile dexFile;
     93 
     94     public HeaderItem(@Nonnull RawDexFile dexFile) {
     95         this.dexFile = dexFile;
     96     }
     97 
     98     public int getChecksum() {
     99         return dexFile.readSmallUint(CHECKSUM_OFFSET);
    100     }
    101 
    102     @Nonnull public byte[] getSignature() {
    103         return dexFile.readByteRange(SIGNATURE_OFFSET, SIGNATURE_SIZE);
    104     }
    105 
    106     public int getMapOffset() {
    107         return dexFile.readSmallUint(MAP_OFFSET);
    108     }
    109 
    110     public int getHeaderSize() {
    111         return dexFile.readSmallUint(HEADER_SIZE_OFFSET);
    112     }
    113 
    114     public int getStringCount() {
    115         return dexFile.readSmallUint(STRING_COUNT_OFFSET);
    116     }
    117 
    118     public int getStringOffset() {
    119         return dexFile.readSmallUint(STRING_START_OFFSET);
    120     }
    121 
    122     public int getTypeCount() {
    123         return dexFile.readSmallUint(TYPE_COUNT_OFFSET);
    124     }
    125 
    126     public int getTypeOffset() {
    127         return dexFile.readSmallUint(TYPE_START_OFFSET);
    128     }
    129 
    130     public int getProtoCount() {
    131         return dexFile.readSmallUint(PROTO_COUNT_OFFSET);
    132     }
    133 
    134     public int getProtoOffset() {
    135         return dexFile.readSmallUint(PROTO_START_OFFSET);
    136     }
    137 
    138     public int getFieldCount() {
    139         return dexFile.readSmallUint(FIELD_COUNT_OFFSET);
    140     }
    141 
    142     public int getFieldOffset() {
    143         return dexFile.readSmallUint(FIELD_START_OFFSET);
    144     }
    145 
    146     public int getMethodCount() {
    147         return dexFile.readSmallUint(METHOD_COUNT_OFFSET);
    148     }
    149 
    150     public int getMethodOffset() {
    151         return dexFile.readSmallUint(METHOD_START_OFFSET);
    152     }
    153 
    154     public int getClassCount() {
    155         return dexFile.readSmallUint(CLASS_COUNT_OFFSET);
    156     }
    157 
    158     public int getClassOffset() {
    159         return dexFile.readSmallUint(CLASS_START_OFFSET);
    160     }
    161 
    162     @Nonnull
    163     public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) {
    164         return new SectionAnnotator(annotator, mapItem) {
    165             @Nonnull @Override public String getItemName() {
    166                 return "header_item";
    167             }
    168 
    169             @Override
    170             protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
    171                 int startOffset = out.getCursor();
    172                 int headerSize;
    173 
    174                 StringBuilder magicBuilder = new StringBuilder();
    175                 for (int i=0; i<8; i++) {
    176                     magicBuilder.append((char)dexFile.readUbyte(startOffset + i));
    177                 }
    178 
    179                 out.annotate(8, "magic: %s", StringUtils.escapeString(magicBuilder.toString()));
    180                 out.annotate(4, "checksum");
    181                 out.annotate(20, "signature");
    182                 out.annotate(4, "file_size: %d", dexFile.readInt(out.getCursor()));
    183 
    184                 headerSize = dexFile.readInt(out.getCursor());
    185                 out.annotate(4, "header_size: %d", headerSize);
    186 
    187                 int endianTag = dexFile.readInt(out.getCursor());
    188                 out.annotate(4, "endian_tag: 0x%x (%s)", endianTag, getEndianText(endianTag));
    189 
    190                 out.annotate(4, "link_size: %d", dexFile.readInt(out.getCursor()));
    191                 out.annotate(4, "link_offset: 0x%x", dexFile.readInt(out.getCursor()));
    192 
    193                 out.annotate(4, "map_off: 0x%x", dexFile.readInt(out.getCursor()));
    194 
    195                 out.annotate(4, "string_ids_size: %d", dexFile.readInt(out.getCursor()));
    196                 out.annotate(4, "string_ids_off: 0x%x", dexFile.readInt(out.getCursor()));
    197 
    198                 out.annotate(4, "type_ids_size: %d", dexFile.readInt(out.getCursor()));
    199                 out.annotate(4, "type_ids_off: 0x%x", dexFile.readInt(out.getCursor()));
    200 
    201                 out.annotate(4, "proto_ids_size: %d", dexFile.readInt(out.getCursor()));
    202                 out.annotate(4, "proto_ids_off: 0x%x", dexFile.readInt(out.getCursor()));
    203 
    204                 out.annotate(4, "field_ids_size: %d", dexFile.readInt(out.getCursor()));
    205                 out.annotate(4, "field_ids_off: 0x%x", dexFile.readInt(out.getCursor()));
    206 
    207                 out.annotate(4, "method_ids_size: %d", dexFile.readInt(out.getCursor()));
    208                 out.annotate(4, "method_ids_off: 0x%x", dexFile.readInt(out.getCursor()));
    209 
    210                 out.annotate(4, "class_defs_size: %d", dexFile.readInt(out.getCursor()));
    211                 out.annotate(4, "class_defs_off: 0x%x", dexFile.readInt(out.getCursor()));
    212 
    213                 out.annotate(4, "data_size: %d", dexFile.readInt(out.getCursor()));
    214                 out.annotate(4, "data_off: 0x%x", dexFile.readInt(out.getCursor()));
    215 
    216                 if (headerSize > ITEM_SIZE) {
    217                     out.annotateTo(headerSize, "header padding");
    218                 }
    219             }
    220         };
    221     }
    222 
    223     private static String getEndianText(int endianTag) {
    224         if (endianTag == LITTLE_ENDIAN_TAG) {
    225             return "Little Endian";
    226         }
    227         if (endianTag == BIG_ENDIAN_TAG) {
    228             return "Big Endian";
    229         }
    230         return "Invalid";
    231     }
    232 
    233 
    234     /**
    235      * Get the higest magic number supported by Android for this api level.
    236      * @return The dex file magic number
    237      */
    238     public static byte[] getMagicForApi(int api) {
    239         if (api < 24) {
    240             // Prior to Android N we only support dex version 035.
    241             return HeaderItem.MAGIC_VALUES[0];
    242         } else {
    243             // On android N and later we support dex version 037.
    244             return HeaderItem.MAGIC_VALUES[1];
    245         }
    246     }
    247 
    248     private static int getVersion(byte[] buf, int offset) {
    249         if (buf.length - offset < 8) {
    250             return 0;
    251         }
    252 
    253         boolean matches = true;
    254         for (int i=0; i<MAGIC_VALUES.length; i++) {
    255             byte[] expected = MAGIC_VALUES[i];
    256             matches = true;
    257             for (int j=0; j<8; j++) {
    258                 if (buf[offset + j] != expected[j]) {
    259                     matches = false;
    260                     break;
    261                 }
    262             }
    263             if (matches) {
    264                 return i==0?35:37;
    265             }
    266         }
    267         return 0;
    268     }
    269 
    270     public static boolean verifyMagic(byte[] buf, int offset) {
    271         // verifies the magic value
    272         return getVersion(buf, offset) != 0;
    273     }
    274 
    275 
    276     public static int getEndian(byte[] buf, int offset) {
    277         BaseDexBuffer bdb = new BaseDexBuffer(buf);
    278         return bdb.readInt(offset + ENDIAN_TAG_OFFSET);
    279     }
    280 }
    281