• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HeaderItem(@onnull RawDexFile dexFile)94     public HeaderItem(@Nonnull RawDexFile dexFile) {
95         this.dexFile = dexFile;
96     }
97 
getChecksum()98     public int getChecksum() {
99         return dexFile.readSmallUint(CHECKSUM_OFFSET);
100     }
101 
getSignature()102     @Nonnull public byte[] getSignature() {
103         return dexFile.readByteRange(SIGNATURE_OFFSET, SIGNATURE_SIZE);
104     }
105 
getMapOffset()106     public int getMapOffset() {
107         return dexFile.readSmallUint(MAP_OFFSET);
108     }
109 
getHeaderSize()110     public int getHeaderSize() {
111         return dexFile.readSmallUint(HEADER_SIZE_OFFSET);
112     }
113 
getStringCount()114     public int getStringCount() {
115         return dexFile.readSmallUint(STRING_COUNT_OFFSET);
116     }
117 
getStringOffset()118     public int getStringOffset() {
119         return dexFile.readSmallUint(STRING_START_OFFSET);
120     }
121 
getTypeCount()122     public int getTypeCount() {
123         return dexFile.readSmallUint(TYPE_COUNT_OFFSET);
124     }
125 
getTypeOffset()126     public int getTypeOffset() {
127         return dexFile.readSmallUint(TYPE_START_OFFSET);
128     }
129 
getProtoCount()130     public int getProtoCount() {
131         return dexFile.readSmallUint(PROTO_COUNT_OFFSET);
132     }
133 
getProtoOffset()134     public int getProtoOffset() {
135         return dexFile.readSmallUint(PROTO_START_OFFSET);
136     }
137 
getFieldCount()138     public int getFieldCount() {
139         return dexFile.readSmallUint(FIELD_COUNT_OFFSET);
140     }
141 
getFieldOffset()142     public int getFieldOffset() {
143         return dexFile.readSmallUint(FIELD_START_OFFSET);
144     }
145 
getMethodCount()146     public int getMethodCount() {
147         return dexFile.readSmallUint(METHOD_COUNT_OFFSET);
148     }
149 
getMethodOffset()150     public int getMethodOffset() {
151         return dexFile.readSmallUint(METHOD_START_OFFSET);
152     }
153 
getClassCount()154     public int getClassCount() {
155         return dexFile.readSmallUint(CLASS_COUNT_OFFSET);
156     }
157 
getClassOffset()158     public int getClassOffset() {
159         return dexFile.readSmallUint(CLASS_START_OFFSET);
160     }
161 
162     @Nonnull
makeAnnotator(@onnull DexAnnotator annotator, @Nonnull MapItem mapItem)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