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", "dex\n037\0", and "dex\n038\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 new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00}}; 54 55 public static final int LITTLE_ENDIAN_TAG = 0x12345678; 56 public static final int BIG_ENDIAN_TAG = 0x78563412; 57 58 public static final int CHECKSUM_OFFSET = 8; 59 60 // this is the start of the checksumed data 61 public static final int CHECKSUM_DATA_START_OFFSET = 12; 62 public static final int SIGNATURE_OFFSET = 12; 63 public static final int SIGNATURE_SIZE = 20; 64 65 // this is the start of the sha-1 hashed data 66 public static final int SIGNATURE_DATA_START_OFFSET = 32; 67 public static final int FILE_SIZE_OFFSET = 32; 68 69 public static final int HEADER_SIZE_OFFSET = 36; 70 71 public static final int ENDIAN_TAG_OFFSET = 40; 72 73 public static final int MAP_OFFSET = 52; 74 75 public static final int STRING_COUNT_OFFSET = 56; 76 public static final int STRING_START_OFFSET = 60; 77 78 public static final int TYPE_COUNT_OFFSET = 64; 79 public static final int TYPE_START_OFFSET = 68; 80 81 public static final int PROTO_COUNT_OFFSET = 72; 82 public static final int PROTO_START_OFFSET = 76; 83 84 public static final int FIELD_COUNT_OFFSET = 80; 85 public static final int FIELD_START_OFFSET = 84; 86 87 public static final int METHOD_COUNT_OFFSET = 88; 88 public static final int METHOD_START_OFFSET = 92; 89 90 public static final int CLASS_COUNT_OFFSET = 96; 91 public static final int CLASS_START_OFFSET = 100; 92 93 @Nonnull private RawDexFile dexFile; 94 HeaderItem(@onnull RawDexFile dexFile)95 public HeaderItem(@Nonnull RawDexFile dexFile) { 96 this.dexFile = dexFile; 97 } 98 getChecksum()99 public int getChecksum() { 100 return dexFile.readSmallUint(CHECKSUM_OFFSET); 101 } 102 getSignature()103 @Nonnull public byte[] getSignature() { 104 return dexFile.readByteRange(SIGNATURE_OFFSET, SIGNATURE_SIZE); 105 } 106 getMapOffset()107 public int getMapOffset() { 108 return dexFile.readSmallUint(MAP_OFFSET); 109 } 110 getHeaderSize()111 public int getHeaderSize() { 112 return dexFile.readSmallUint(HEADER_SIZE_OFFSET); 113 } 114 getStringCount()115 public int getStringCount() { 116 return dexFile.readSmallUint(STRING_COUNT_OFFSET); 117 } 118 getStringOffset()119 public int getStringOffset() { 120 return dexFile.readSmallUint(STRING_START_OFFSET); 121 } 122 getTypeCount()123 public int getTypeCount() { 124 return dexFile.readSmallUint(TYPE_COUNT_OFFSET); 125 } 126 getTypeOffset()127 public int getTypeOffset() { 128 return dexFile.readSmallUint(TYPE_START_OFFSET); 129 } 130 getProtoCount()131 public int getProtoCount() { 132 return dexFile.readSmallUint(PROTO_COUNT_OFFSET); 133 } 134 getProtoOffset()135 public int getProtoOffset() { 136 return dexFile.readSmallUint(PROTO_START_OFFSET); 137 } 138 getFieldCount()139 public int getFieldCount() { 140 return dexFile.readSmallUint(FIELD_COUNT_OFFSET); 141 } 142 getFieldOffset()143 public int getFieldOffset() { 144 return dexFile.readSmallUint(FIELD_START_OFFSET); 145 } 146 getMethodCount()147 public int getMethodCount() { 148 return dexFile.readSmallUint(METHOD_COUNT_OFFSET); 149 } 150 getMethodOffset()151 public int getMethodOffset() { 152 return dexFile.readSmallUint(METHOD_START_OFFSET); 153 } 154 getClassCount()155 public int getClassCount() { 156 return dexFile.readSmallUint(CLASS_COUNT_OFFSET); 157 } 158 getClassOffset()159 public int getClassOffset() { 160 return dexFile.readSmallUint(CLASS_START_OFFSET); 161 } 162 163 @Nonnull makeAnnotator(@onnull DexAnnotator annotator, @Nonnull MapItem mapItem)164 public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { 165 return new SectionAnnotator(annotator, mapItem) { 166 @Nonnull @Override public String getItemName() { 167 return "header_item"; 168 } 169 170 @Override 171 protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { 172 int startOffset = out.getCursor(); 173 int headerSize; 174 175 StringBuilder magicBuilder = new StringBuilder(); 176 for (int i=0; i<8; i++) { 177 magicBuilder.append((char)dexFile.readUbyte(startOffset + i)); 178 } 179 180 out.annotate(8, "magic: %s", StringUtils.escapeString(magicBuilder.toString())); 181 out.annotate(4, "checksum"); 182 out.annotate(20, "signature"); 183 out.annotate(4, "file_size: %d", dexFile.readInt(out.getCursor())); 184 185 headerSize = dexFile.readInt(out.getCursor()); 186 out.annotate(4, "header_size: %d", headerSize); 187 188 int endianTag = dexFile.readInt(out.getCursor()); 189 out.annotate(4, "endian_tag: 0x%x (%s)", endianTag, getEndianText(endianTag)); 190 191 out.annotate(4, "link_size: %d", dexFile.readInt(out.getCursor())); 192 out.annotate(4, "link_offset: 0x%x", dexFile.readInt(out.getCursor())); 193 194 out.annotate(4, "map_off: 0x%x", dexFile.readInt(out.getCursor())); 195 196 out.annotate(4, "string_ids_size: %d", dexFile.readInt(out.getCursor())); 197 out.annotate(4, "string_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 198 199 out.annotate(4, "type_ids_size: %d", dexFile.readInt(out.getCursor())); 200 out.annotate(4, "type_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 201 202 out.annotate(4, "proto_ids_size: %d", dexFile.readInt(out.getCursor())); 203 out.annotate(4, "proto_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 204 205 out.annotate(4, "field_ids_size: %d", dexFile.readInt(out.getCursor())); 206 out.annotate(4, "field_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 207 208 out.annotate(4, "method_ids_size: %d", dexFile.readInt(out.getCursor())); 209 out.annotate(4, "method_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 210 211 out.annotate(4, "class_defs_size: %d", dexFile.readInt(out.getCursor())); 212 out.annotate(4, "class_defs_off: 0x%x", dexFile.readInt(out.getCursor())); 213 214 out.annotate(4, "data_size: %d", dexFile.readInt(out.getCursor())); 215 out.annotate(4, "data_off: 0x%x", dexFile.readInt(out.getCursor())); 216 217 if (headerSize > ITEM_SIZE) { 218 out.annotateTo(headerSize, "header padding"); 219 } 220 } 221 }; 222 } 223 224 private static String getEndianText(int endianTag) { 225 if (endianTag == LITTLE_ENDIAN_TAG) { 226 return "Little Endian"; 227 } 228 if (endianTag == BIG_ENDIAN_TAG) { 229 return "Big Endian"; 230 } 231 return "Invalid"; 232 } 233 234 235 /** 236 * Get the higest magic number supported by Android for this api level. 237 * @return The dex file magic number 238 */ 239 public static byte[] getMagicForApi(int api) { 240 if (api < 24) { 241 // Prior to Android N we only support dex version 035. 242 return HeaderItem.MAGIC_VALUES[0]; 243 } else if (api < 26) { 244 // On android N and later we support dex version 037. 245 return HeaderItem.MAGIC_VALUES[1]; 246 } else { 247 // On android O and later we support dex version 038. 248 return HeaderItem.MAGIC_VALUES[2]; 249 } 250 } 251 252 private static int getVersion(byte[] buf, int offset) { 253 if (buf.length - offset < 8) { 254 return 0; 255 } 256 257 boolean matches = true; 258 for (int i=0; i<MAGIC_VALUES.length; i++) { 259 byte[] expected = MAGIC_VALUES[i]; 260 matches = true; 261 for (int j=0; j<8; j++) { 262 if (buf[offset + j] != expected[j]) { 263 matches = false; 264 break; 265 } 266 } 267 if (matches) { 268 return i==0?35:(i==1?37:38); 269 } 270 } 271 return 0; 272 } 273 274 public static boolean verifyMagic(byte[] buf, int offset) { 275 // verifies the magic value 276 return getVersion(buf, offset) != 0; 277 } 278 279 280 public static int getEndian(byte[] buf, int offset) { 281 BaseDexBuffer bdb = new BaseDexBuffer(buf); 282 return bdb.readInt(offset + ENDIAN_TAG_OFFSET); 283 } 284 } 285