From 73a63516fc1b0eeac382a33e913980643efdc700 Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Sun, 30 Aug 2009 02:32:27 +0000 Subject: [PATCH] preliminary support for reading in odex files git-svn-id: https://smali.googlecode.com/svn/trunk@431 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../src/main/java/org/jf/dexlib/DexFile.java | 36 ++++++++- .../main/java/org/jf/dexlib/HeaderItem.java | 4 +- .../java/org/jf/dexlib/OdexHeaderItem.java | 78 +++++++++++++++++++ .../java/org/jf/dexlib/Util/FileUtils.java | 37 ++++++++- 4 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 dexlib/src/main/java/org/jf/dexlib/OdexHeaderItem.java diff --git a/dexlib/src/main/java/org/jf/dexlib/DexFile.java b/dexlib/src/main/java/org/jf/dexlib/DexFile.java index a1d213ab..16b1e0d5 100644 --- a/dexlib/src/main/java/org/jf/dexlib/DexFile.java +++ b/dexlib/src/main/java/org/jf/dexlib/DexFile.java @@ -34,6 +34,7 @@ import org.jf.dexlib.Item; import org.jf.dexlib.StringDataItem; import java.io.File; +import java.io.UnsupportedEncodingException; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -266,7 +267,40 @@ public class DexFile public DexFile(File file, boolean preserveSignedRegisters) { this(preserveSignedRegisters); - Input in = new ByteArrayInput(FileUtils.readFile(file)); + byte[] magic = FileUtils.readFile(file, 0, 8); + byte[] dexMagic, odexMagic; + + try { + dexMagic = HeaderItem.MAGIC.getBytes("US-ASCII"); + odexMagic = OdexHeaderItem.MAGIC.getBytes("US-ASCII"); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException(ex); + } + + boolean isDex = true; + boolean isOdex = true; + for (int i=0; i<8; i++) { + if (magic[i] != dexMagic[i]) { + isDex = false; + } + if (magic[i] != odexMagic[i]) { + isOdex = false; + } + } + + Input in; + + if (isOdex) { + byte[] odexHeaderBytes = FileUtils.readFile(file, 0, 40); + Input odexHeaderIn = new ByteArrayInput(odexHeaderBytes); + OdexHeaderItem odexHeader = new OdexHeaderItem(odexHeaderIn); + + in = new ByteArrayInput(FileUtils.readFile(file, odexHeader.dexOffset, odexHeader.dexLength)); + } else if (isDex) { + in = new ByteArrayInput(FileUtils.readFile(file)); + } else { + throw new RuntimeException("bad magic value"); + } ReadContext readContext = new ReadContext(this); diff --git a/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java b/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java index c971e971..31e2a1a1 100644 --- a/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/HeaderItem.java @@ -36,10 +36,10 @@ import java.io.UnsupportedEncodingException; public class HeaderItem extends Item { /** - * non-null; the file format magic number, represented as the + * the file format magic number, represented as the * low-order bytes of a string */ - private static final String MAGIC = "dex\n035" + '\0'; + public static final String MAGIC = "dex\n035" + '\0'; /** size of this section, in bytes */ private static final int HEADER_SIZE = 0x70; diff --git a/dexlib/src/main/java/org/jf/dexlib/OdexHeaderItem.java b/dexlib/src/main/java/org/jf/dexlib/OdexHeaderItem.java new file mode 100644 index 00000000..19592a4f --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/OdexHeaderItem.java @@ -0,0 +1,78 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib; + +import org.jf.dexlib.Util.Input; + +import java.io.UnsupportedEncodingException; + +public class OdexHeaderItem { + + /** + * the file format magic number, represented as the + * low-order bytes of a string + */ + public static final String MAGIC = "dey\n035" + '\0'; + + public final byte[] magic; + public final int dexOffset; + public final int dexLength; + public final int depsOffset; + public final int depsLength; + public final int auxOffset; + public final int auxLength; + public final int flags; + + public OdexHeaderItem(Input in) { + magic = in.readBytes(8); + + byte[] expectedMagic; + try { + expectedMagic = MAGIC.getBytes("US-ASCII"); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException(ex); + } + + for (int i=0; i<8; i++) { + if (expectedMagic[i] != magic[i]) { + throw new RuntimeException("The magic value is not the expected value"); + } + } + + dexOffset = in.readInt(); + dexLength = in.readInt(); + depsOffset = in.readInt(); + depsLength = in.readInt(); + auxOffset = in.readInt(); + auxLength = in.readInt(); + flags = in.readInt(); + in.readInt(); //padding + } + +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/FileUtils.java b/dexlib/src/main/java/org/jf/dexlib/Util/FileUtils.java index 2da3baec..e081a832 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/FileUtils.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/FileUtils.java @@ -51,6 +51,20 @@ public final class FileUtils { * @return non-null; contents of the file */ public static byte[] readFile(File file) { + return readFile(file, 0, -1); + } + + /** + * Reads the specified block from the given file, translating + * {@link IOException} to a {@link RuntimeException} of some sort. + * + * @param file non-null; the file to read + * @param offset the offset to begin reading + * @param length the number of bytes to read, or -1 to read to the + * end of the file + * @return non-null; contents of the file + */ + public static byte[] readFile(File file, int offset, int length) { if (!file.exists()) { throw new RuntimeException(file + ": file not found"); } @@ -64,16 +78,33 @@ public final class FileUtils { } long longLength = file.length(); - int length = (int) longLength; - if (length != longLength) { + int fileLength = (int) longLength; + if (fileLength != longLength) { throw new RuntimeException(file + ": file too long"); } + if (length == -1) { + length = fileLength - offset; + } + + if (offset + length > fileLength) { + throw new RuntimeException(file + ": file too short"); + } + byte[] result = new byte[length]; try { FileInputStream in = new FileInputStream(file); - int at = 0; + + int at = offset; + while(at > 0) { + long amt = in.skip(at); + if (amt == -1) { + throw new RuntimeException(file + ": unexpected EOF"); + } + at -= amt; + } + while (length > 0) { int amt = in.read(result, at, length); if (amt == -1) {