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