HeaderItem.java revision d45a6a60921ac27a4f13360a68e02e8f5fc28454
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 32package org.jf.dexlib2.dexbacked.raw; 33 34import org.jf.dexlib2.dexbacked.BaseDexBuffer; 35import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator; 36import org.jf.dexlib2.util.AnnotatedBytes; 37import org.jf.util.StringUtils; 38 39import javax.annotation.Nonnull; 40import javax.annotation.Nullable; 41 42public class HeaderItem { 43 public static final int ITEM_SIZE = 0x70; 44 45 public static final byte[][] MAGIC_VALUES= new byte[][] { 46 new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00}, 47 new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x36, 0x00}}; 48 49 public static final int LITTLE_ENDIAN_TAG = 0x12345678; 50 public static final int BIG_ENDIAN_TAG = 0x78563412; 51 52 public static final int CHECKSUM_OFFSET = 8; 53 54 public static final int SIGNATURE_OFFSET = 12; 55 public static final int SIGNATURE_SIZE = 20; 56 57 public static final int HEADER_SIZE_OFFSET = 36; 58 59 public static final int ENDIAN_TAG_OFFSET = 40; 60 61 public static final int MAP_OFFSET = 52; 62 63 public static final int STRING_COUNT_OFFSET = 56; 64 public static final int STRING_START_OFFSET = 60; 65 66 public static final int TYPE_COUNT_OFFSET = 64; 67 public static final int TYPE_START_OFFSET = 68; 68 69 public static final int PROTO_COUNT_OFFSET = 72; 70 public static final int PROTO_START_OFFSET = 76; 71 72 public static final int FIELD_COUNT_OFFSET = 80; 73 public static final int FIELD_START_OFFSET = 84; 74 75 public static final int METHOD_COUNT_OFFSET = 88; 76 public static final int METHOD_START_OFFSET = 92; 77 78 public static final int CLASS_COUNT_OFFSET = 96; 79 public static final int CLASS_START_OFFSET = 100; 80 81 @Nonnull private RawDexFile dexFile; 82 83 public HeaderItem(@Nonnull RawDexFile dexFile) { 84 this.dexFile = dexFile; 85 } 86 87 public int getChecksum() { 88 return dexFile.readSmallUint(CHECKSUM_OFFSET); 89 } 90 91 @Nonnull public byte[] getSignature() { 92 return dexFile.readByteRange(SIGNATURE_OFFSET, SIGNATURE_SIZE); 93 } 94 95 public int getMapOffset() { 96 return dexFile.readSmallUint(MAP_OFFSET); 97 } 98 99 public int getHeaderSize() { 100 return dexFile.readSmallUint(HEADER_SIZE_OFFSET); 101 } 102 103 public int getStringCount() { 104 return dexFile.readSmallUint(STRING_COUNT_OFFSET); 105 } 106 107 public int getStringOffset() { 108 return dexFile.readSmallUint(STRING_START_OFFSET); 109 } 110 111 public int getTypeCount() { 112 return dexFile.readSmallUint(TYPE_COUNT_OFFSET); 113 } 114 115 public int getTypeOffset() { 116 return dexFile.readSmallUint(TYPE_START_OFFSET); 117 } 118 119 public int getProtoCount() { 120 return dexFile.readSmallUint(PROTO_COUNT_OFFSET); 121 } 122 123 public int getProtoOffset() { 124 return dexFile.readSmallUint(PROTO_START_OFFSET); 125 } 126 127 public int getFieldCount() { 128 return dexFile.readSmallUint(FIELD_COUNT_OFFSET); 129 } 130 131 public int getFieldOffset() { 132 return dexFile.readSmallUint(FIELD_START_OFFSET); 133 } 134 135 public int getMethodCount() { 136 return dexFile.readSmallUint(METHOD_COUNT_OFFSET); 137 } 138 139 public int getMethodOffset() { 140 return dexFile.readSmallUint(METHOD_START_OFFSET); 141 } 142 143 public int getClassCount() { 144 return dexFile.readSmallUint(CLASS_COUNT_OFFSET); 145 } 146 147 public int getClassOffset() { 148 return dexFile.readSmallUint(CLASS_START_OFFSET); 149 } 150 151 @Nonnull 152 public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { 153 return new SectionAnnotator(annotator, mapItem) { 154 @Nonnull @Override public String getItemName() { 155 return "header_item"; 156 } 157 158 @Override 159 protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { 160 int startOffset = out.getCursor(); 161 int headerSize; 162 163 StringBuilder magicBuilder = new StringBuilder(); 164 for (int i=0; i<8; i++) { 165 magicBuilder.append((char)dexFile.readUbyte(startOffset + i)); 166 } 167 168 out.annotate(8, "magic: %s", StringUtils.escapeString(magicBuilder.toString())); 169 out.annotate(4, "checksum"); 170 out.annotate(20, "signature"); 171 out.annotate(4, "file_size: %d", dexFile.readInt(out.getCursor())); 172 173 headerSize = dexFile.readInt(out.getCursor()); 174 out.annotate(4, "header_size: %d", headerSize); 175 176 int endianTag = dexFile.readInt(out.getCursor()); 177 out.annotate(4, "endian_tag: 0x%x (%s)", endianTag, getEndianText(endianTag)); 178 179 out.annotate(4, "link_size: %d", dexFile.readInt(out.getCursor())); 180 out.annotate(4, "link_offset: 0x%x", dexFile.readInt(out.getCursor())); 181 182 out.annotate(4, "map_off: 0x%x", dexFile.readInt(out.getCursor())); 183 184 out.annotate(4, "string_ids_size: %d", dexFile.readInt(out.getCursor())); 185 out.annotate(4, "string_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 186 187 out.annotate(4, "type_ids_size: %d", dexFile.readInt(out.getCursor())); 188 out.annotate(4, "type_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 189 190 out.annotate(4, "proto_ids_size: %d", dexFile.readInt(out.getCursor())); 191 out.annotate(4, "proto_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 192 193 out.annotate(4, "field_ids_size: %d", dexFile.readInt(out.getCursor())); 194 out.annotate(4, "field_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 195 196 out.annotate(4, "method_ids_size: %d", dexFile.readInt(out.getCursor())); 197 out.annotate(4, "method_ids_off: 0x%x", dexFile.readInt(out.getCursor())); 198 199 out.annotate(4, "class_defs_size: %d", dexFile.readInt(out.getCursor())); 200 out.annotate(4, "class_defs_off: 0x%x", dexFile.readInt(out.getCursor())); 201 202 out.annotate(4, "data_size: %d", dexFile.readInt(out.getCursor())); 203 out.annotate(4, "data_off: 0x%x", dexFile.readInt(out.getCursor())); 204 205 if (headerSize > ITEM_SIZE) { 206 out.annotateTo(headerSize, "header padding"); 207 } 208 } 209 }; 210 } 211 212 private static String getEndianText(int endianTag) { 213 if (endianTag == LITTLE_ENDIAN_TAG) { 214 return "Little Endian"; 215 } 216 if (endianTag == BIG_ENDIAN_TAG) { 217 return "Big Endian"; 218 } 219 return "Invalid"; 220 } 221 222 private static int getVersion(byte[] buf, int offset) { 223 if (buf.length - offset < 8) { 224 return 0; 225 } 226 227 boolean matches = true; 228 for (int i=0; i<MAGIC_VALUES.length; i++) { 229 byte[] expected = MAGIC_VALUES[i]; 230 matches = true; 231 for (int j=0; j<8; j++) { 232 if (buf[offset + j] != expected[j]) { 233 matches = false; 234 break; 235 } 236 } 237 if (matches) { 238 return i==0?35:36; 239 } 240 } 241 return 0; 242 } 243 244 public static boolean verifyMagic(byte[] buf, int offset) { 245 // verifies the magic value 246 return getVersion(buf, offset) != 0; 247 } 248 249 250 public static int getEndian(byte[] buf, int offset) { 251 BaseDexBuffer bdb = new BaseDexBuffer(buf); 252 return bdb.readInt(offset + ENDIAN_TAG_OFFSET); 253 } 254} 255