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