• 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", "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